package com.heyu.api.controller.car;

import com.heyu.api.baidu.request.traffic.BVehicleLicenseRequest;
import com.heyu.api.controller.BaseController;
import com.heyu.api.data.annotation.EbAuthentication;
import com.heyu.api.data.constants.ApiConstants;
import com.heyu.api.data.utils.MapUtils;
import com.heyu.api.data.utils.R;
import com.heyu.api.data.utils.StringUtils;
import com.heyu.api.request.car.VehicleLicenseRequest;
import com.heyu.api.resp.car.RecognizeDrivingLicenseBackResp;
import com.heyu.api.resp.car.RecognizeDrivingLicenseFaceResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


/**
 * 行驶证识别控制器
 *
 * <p>提供行驶证OCR识别功能，基于百度云交通场景OCR接口实现</p>
 * <p>支持功能：</p>
 * <ul>
 *   <li>行驶证正面识别：包含号牌号码、车辆类型、所有人、使用性质等基本信息</li>
 *   <li>行驶证反面识别：包含核定载人数、总质量、检验记录等详细信息</li>
 *   <li>支持图片URL和Base64两种输入方式</li>
 *   <li>支持图像方向自动矫正、质量告警等高级功能</li>
 * </ul>
 *
 * <p>接口文档：https://console.bce.baidu.com/support/#/api?product=AI&project=文字识别&parent=交通场景OCR&api=rest%2F2.0%2Focr%2Fv1%2Fvehicle_license&method=post</p>
 *
 * @author heyu
 * @since 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/driving/license")
@SuppressWarnings("unchecked")
public class RecognizeDrivingLicenseController extends BaseController {

    private static final String VEHICLE_LICENSE_URI = "/rest/2.0/ocr/v1/vehicle_license";

    /**
     * 行驶证识别接口
     * 支持行驶证正反面识别，使用百度云OCR接口
     *
     * @param request 行驶证识别请求对象，包含图片URL或base64编码、正反面标识等参数
     * @return 识别结果，正面返回 {@link RecognizeDrivingLicenseFaceResp}，反面返回 {@link RecognizeDrivingLicenseBackResp}
     */
    @EbAuthentication(tencent = ApiConstants.TENCENT_AUTH)
    @PostMapping("/recognize")
    public R<Object> recognize(@RequestBody VehicleLicenseRequest request) {
        long start = System.currentTimeMillis();

        long t1 = System.currentTimeMillis();
        BVehicleLicenseRequest bVehicleLicenseRequest = toBaiduRequest(request);
        String checkMsg = checkRequest(bVehicleLicenseRequest);
        if (!isBlank(checkMsg)) {
            return R.error(checkMsg);
        }
        log.info("行驶证识别-参数校验及构建请求耗时:{}ms", System.currentTimeMillis() - t1);

        long t2 = System.currentTimeMillis();
        Map<String, Object> data = requestBaidu(VEHICLE_LICENSE_URI, getContent(bVehicleLicenseRequest));
        long baiduCost = System.currentTimeMillis() - t2;
        log.info("行驶证识别-调用百度OCR接口耗时:{}ms", baiduCost);

        if (data == null) {
            log.info("行驶证识别-识别失败, 耗时:{}ms", System.currentTimeMillis() - start);
            return R.error("行驶证识别失败");
        }

        long t3 = System.currentTimeMillis();
        R<Object> result = R.ok();
        result.setData(toRecognizeResp(bVehicleLicenseRequest.getVehicleLicenseSide(), data));
        log.info("行驶证识别-结果映射耗时:{}ms", System.currentTimeMillis() - t3);

        log.info("行驶证识别-总耗时:{}ms, 其中第三方(百度OCR):{}ms", System.currentTimeMillis() - start, baiduCost);
        return result;
    }

    /**
     * 将前端请求对象转换为百度云请求对象
     *
     * @param request 前端行驶证识别请求
     * @return 百度云行驶证识别请求对象
     */
    private BVehicleLicenseRequest toBaiduRequest(VehicleLicenseRequest request) {
        BVehicleLicenseRequest bVehicleLicenseRequest = new BVehicleLicenseRequest();
        if (request == null) {
            return bVehicleLicenseRequest;
        }
        bVehicleLicenseRequest.setImageUrl(request.getImageUrl());
        bVehicleLicenseRequest.setImageBase64(request.getImageBase64());
        if (StringUtils.isNotBlank(request.getSide())) {
            bVehicleLicenseRequest.setVehicleLicenseSide(request.getSide());
        }
        return bVehicleLicenseRequest;
    }

    /**
     * 校验请求参数的合法性
     *
     * @param request 百度云请求对象
     * @return 校验通过返回null，否则返回错误信息
     */
    private String checkRequest(BVehicleLicenseRequest request) {
        if (!hasImage(request)) {
            return "imageUrl和imageBase64不能同时为空";
        }
        if (checkNotTrueFalse(request.getDetectDirection())) {
            return "detectDirection 必须传 " + ApiConstants.trueOrFalse + ",false：不进行图像方向自动矫正, true: 开启图像方向自动矫正功能，可对旋转 90/180/270 度的图片进行自动矫正并识别";
        }
        if (checkNotFrontBack(request.getVehicleLicenseSide())) {
            return "front 必须传 " + ApiConstants.frontOrback + ",front：正向， back反面";
        }
        if (checkNotTrueFalse(request.getUnified())) {
            return "unified必须为 " + ApiConstants.trueOrFalse + ", false 不进行归一化处理, rue：对输出字段进行归一化处理，将新/老版行驶证的“注册登记日期/注册日期”统一为”注册日期“进行输出";
        }
        if (checkNotTrueFalse(request.getQualityWarn())) {
            return "qualityWarn 必须为" + ApiConstants.trueOrFalse + ",false：不输出质量告警信息, true : 输出行驶证遮挡、不完整质量告警信息";
        }
        return null;
    }

    /**
     * 检查请求中是否包含有效的图片数据
     *
     * @param request 百度云请求对象
     * @return 如果包含imageUrl或imageBase64则返回true
     */
    private boolean hasImage(BVehicleLicenseRequest request) {
        return request != null && (!isBlank(request.getImageUrl()) || !isBlank(request.getImageBase64()));
    }

    /**
     * 构建百度云OCR接口的请求参数字符串
     *
     * @param request 百度云请求对象
     * @return HTTP请求参数字符串
     */
    private String getContent(BVehicleLicenseRequest request) {
        StringBuffer sb = getImageContent(request);
        if (StringUtils.isNotBlank(request.getDetectDirection())) {
            sb.append("&detect_direction=").append(request.getDetectDirection());
        }
        if (StringUtils.isNotBlank(request.getVehicleLicenseSide())) {
            sb.append("&vehicle_license_side=").append(request.getVehicleLicenseSide());
        }
        if (StringUtils.isNotBlank(request.getUnified())) {
            sb.append("&unified=").append(request.getUnified());
        }
        if (StringUtils.isNotBlank(request.getQualityWarn())) {
            sb.append("&quality_warn=").append(request.getQualityWarn());
        }
        if (StringUtils.isNotBlank(request.getRiskWarn())) {
            sb.append("&risk_warn=").append(request.getRiskWarn());
        }
        return sb.toString();
    }

    /**
     * 获取图片相关的请求参数
     *
     * @param request 百度云请求对象
     * @return 包含image或url参数的StringBuffer
     */
    private StringBuffer getImageContent(BVehicleLicenseRequest request) {
        StringBuffer sb = new StringBuffer();
        if (StringUtils.isNotBlank(request.getImageBase64())) {
            sb.append("&image=").append(request.getImageBase64());
        }

        if (StringUtils.isNotBlank(request.getImageUrl())) {
            sb.append("&url=").append(request.getImageUrl());
        }
        return sb;
    }

    /**
     * 检查字符串是否不在允许的true/false范围内
     *
     * @param value 待检查的字符串
     * @return 如果不是"true"或"false"返回true
     */
    private boolean checkNotTrueFalse(String value) {
        return !ApiConstants.trueOrFalse.contains(value);
    }

    /**
     * 检查字符串是否不在允许的front/back范围内
     *
     * @param value 待检查的字符串
     * @return 如果不是"front"或"back"返回true
     */
    private boolean checkNotFrontBack(String value) {
        return !ApiConstants.frontOrback.contains(value);
    }

    /**
     * 根据正反面标识转换为对应的响应对象
     *
     * @param side 行驶证正反面标识（front正面，back反面）
     * @param data 百度云OCR识别的原始数据
     * @return 正面返回 {@link RecognizeDrivingLicenseFaceResp}，反面返回 {@link RecognizeDrivingLicenseBackResp}
     */
    private Object toRecognizeResp(String side, Map<String, Object> data) {
        if (ApiConstants.front.equals(side)) {
            return toFaceResp(data);
        }
        return toBackResp(data);
    }

    /**
     * 将百度云OCR识别结果转换为行驶证正面响应对象
     *
     * @param data 百度云OCR识别的原始数据
     * @return 行驶证正面响应对象，包含号牌号码、车辆类型、所有人等信息
     */
    private RecognizeDrivingLicenseFaceResp toFaceResp(Map<String, Object> data) {
        RecognizeDrivingLicenseFaceResp faceResp = new RecognizeDrivingLicenseFaceResp();
        faceResp.setIssueDate(MapUtils.getByExpr(data, "words_result.发证日期.words"));
        faceResp.setIssueAuthority(MapUtils.getByExpr(data, "words_result.发证单位.words"));
        faceResp.setModel(MapUtils.getByExpr(data, "words_result.品牌型号.words"));
        faceResp.setVehicleType(MapUtils.getByExpr(data, "words_result.车辆类型.words"));
        faceResp.setOwner(MapUtils.getByExpr(data, "words_result.所有人.words"));
        faceResp.setEngineNumber(MapUtils.getByExpr(data, "words_result.发动机号码.words"));
        faceResp.setPlateNumber(MapUtils.getByExpr(data, "words_result.号牌号码.words"));
        faceResp.setAddress(MapUtils.getByExpr(data, "words_result.住址.words"));
        faceResp.setUseCharacter(MapUtils.getByExpr(data, "words_result.使用性质.words"));
        faceResp.setVin(MapUtils.getByExpr(data, "words_result.车辆识别代号.words"));
        faceResp.setRegisterDate(MapUtils.getByExpr(data, "words_result.注册日期.words"));
        return faceResp;
    }

    /**
     * 将百度云OCR识别结果转换为行驶证反面响应对象
     *
     * @param data 百度云OCR识别的原始数据
     * @return 行驶证反面响应对象，包含号牌号码、核定载人数、总质量等信息
     */
    private RecognizeDrivingLicenseBackResp toBackResp(Map<String, Object> data) {
        RecognizeDrivingLicenseBackResp backResp = new RecognizeDrivingLicenseBackResp();
        backResp.setOverallDimension(MapUtils.getByExpr(data, "words_result.外廓尺寸.words"));
        backResp.setInspectionRecord(MapUtils.getByExpr(data, "words_result.检验记录.words"));
        backResp.setUnladenMass(MapUtils.getByExpr(data, "words_result.整备质量.words"));
        backResp.setFileNumber(MapUtils.getByExpr(data, "words_result.档案编号.words"));
        backResp.setTractionMass(MapUtils.getByExpr(data, "words_result.准牵引总质量.words"));
        backResp.setGrossMass(MapUtils.getByExpr(data, "words_result.总质量.words"));
        backResp.setPlateNumber(MapUtils.getByExpr(data, "words_result.号牌号码.words"));
        backResp.setApprovedPassengerCapacity(MapUtils.getByExpr(data, "words_result.核定载人数.words"));
        backResp.setEnergyType(MapUtils.getByExpr(data, "words_result.燃油类型.words"));
        backResp.setApprovedLoad(MapUtils.getByExpr(data, "words_result.核定载质量.words"));
        backResp.setRemark(MapUtils.getByExpr(data, "words_result.备注.words"));
        backResp.setCertificateNumber(MapUtils.getByExpr(data, "words_result.证芯编号.words"));
        return backResp;
    }

}
