package com.heyu.api.controller.car;

import com.heyu.api.baidu.request.traffic.BDriverLicenseRequest;
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.DriverLicenseRecognizeRequest;
import com.heyu.api.resp.car.RecognizeDriverLicenseBackResp;
import com.heyu.api.resp.car.RecognizeDriverLicenseFaceResp;
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;

/**
 * 驾驶证识别（百度OCR）
 *
 * 支持对机动车驾驶证正页及副页所有字段进行结构化识别。
 * 驾驶证正页：证号、姓名、性别、国籍、出生日期、初次领证日期、准驾车型、有效起始日期、失效日期、住址、发证单位 11个字段
 * 驾驶证副页：姓名、记录、证号、档案编号 4个字段
 * 同时支持识别交管12123 APP 发放的电子驾驶证正页，包括证号、姓名、性别、国籍、出生日期、初次领证日期、准驾车型、有效起始日期、失效日期、累积记分、状态、档案编号、生成时间、当前时间、条形码下编号 15个字段
 *
 * 百度文档：https://console.bce.baidu.com/support/#/api?product=AI&project=文字识别&parent=交通场景OCR&api=rest%2F2.0%2Focr%2Fv1%2Fdriving_license&method=post
 */
@Slf4j
@RestController
@RequestMapping("/driver/license")
@SuppressWarnings("unchecked")
public class RecognizeDriverLicenseController extends BaseController {

    private static final String DRIVER_LICENSE_URI = "/rest/2.0/ocr/v1/driving_license";

    @EbAuthentication(tencent = ApiConstants.TENCENT_AUTH)
    @PostMapping("/recognize")
    public R<RecognizeDriverLicenseFaceResp> recognize(@RequestBody DriverLicenseRecognizeRequest request) {
        long start = System.currentTimeMillis();

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

        long t2 = System.currentTimeMillis();
        Map<String, Object> data = requestBaidu(DRIVER_LICENSE_URI, getContent(bRequest));
        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();
        Object resp;
        if (ApiConstants.face.equals(request.getSide())) {
            resp = toFaceResp(data);
        } else {
            resp = toBackResp(data);
        }
        log.info("驾驶证识别-结果映射耗时:{}ms, side:{}", System.currentTimeMillis() - t3, request.getSide());

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

    private BDriverLicenseRequest toBaiduRequest(DriverLicenseRecognizeRequest request) {
        BDriverLicenseRequest bRequest = new BDriverLicenseRequest();
        if (request == null) {
            return bRequest;
        }
        bRequest.setImageBase64(request.getImageBase64());
        bRequest.setImageUrl(request.getImageUrl());

        // 将 "face" 映射为百度API的 "front"
        if (StringUtils.isNotBlank(request.getSide())) {
            if (ApiConstants.face.equals(request.getSide())) {
                bRequest.setDrivingLicenseSide("front");
            } else {
                bRequest.setDrivingLicenseSide(request.getSide());
            }
        }
        return bRequest;
    }

    private String checkRequest(BDriverLicenseRequest request) {
        if (!hasImage(request)) {
            return "imageUrl和imageBase64不能同时为空";
        }
        if (checkNotTrueFalse(request.getDetectDirection())) {
            return "detectDirection 必须传 " + ApiConstants.trueOrFalse
                    + ",false：默认值，不检测朝向, true：检测朝向";
        }
        if (checkNotFrontBack(request.getDrivingLicenseSide())) {
            return "drivingLicenseSide 必须传 " + ApiConstants.frontOrback
                    + ",front：识别驾驶证正页、电子驾驶证正页, back：识别驾驶证副页";
        }
        if (checkNotTrueFalse(request.getUnifiedValidPeriod())) {
            return "unifiedValidPeriod 必须传 " + ApiConstants.trueOrFalse
                    + ",false：默认值，不进行归一化处理, true：归一化格式输出";
        }
        if (checkNotTrueFalse(request.getQualityWarn())) {
            return "qualityWarn 必须传 " + ApiConstants.trueOrFalse
                    + ",false：不输出质量告警信息, true：输出遮挡、不完整质量告警信息";
        }
        if (checkNotTrueFalse(request.getRiskWarn())) {
            return "riskWarn 必须传 " + ApiConstants.trueOrFalse
                    + ",false：不输出风险告警信息, true：开启，输出驾驶正复印、翻拍、PS等告警信息";
        }
        return null;
    }

    private boolean hasImage(BDriverLicenseRequest request) {
        return request != null && (!isBlank(request.getImageUrl()) || !isBlank(request.getImageBase64()));
    }

    private String getContent(BDriverLicenseRequest request) {
        StringBuffer sb = getImageContent(request);
        if (StringUtils.isNotBlank(request.getDetectDirection())) {
            sb.append("&detect_direction=").append(request.getDetectDirection());
        }
        if (StringUtils.isNotBlank(request.getDrivingLicenseSide())) {
            sb.append("&driving_license_side=").append(request.getDrivingLicenseSide());
        }
        if (StringUtils.isNotBlank(request.getUnifiedValidPeriod())) {
            sb.append("&unified_valid_period=").append(request.getUnifiedValidPeriod());
        }
        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();
    }

    private StringBuffer getImageContent(BDriverLicenseRequest 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;
    }

    private boolean checkNotTrueFalse(String value) {
        return !ApiConstants.trueOrFalse.contains(value);
    }

    private boolean checkNotFrontBack(String value) {
        return !ApiConstants.frontOrback.contains(value);
    }

    private RecognizeDriverLicenseFaceResp toFaceResp(Map<String, Object> data) {
        RecognizeDriverLicenseFaceResp resp = new RecognizeDriverLicenseFaceResp();

        // 驾驶证正页 11个字段
        resp.setLicenseNumber(MapUtils.getByExpr(data, "words_result.证号.words"));
        resp.setName(MapUtils.getByExpr(data, "words_result.姓名.words"));
        resp.setGender(MapUtils.getByExpr(data, "words_result.性别.words"));
        resp.setNationality(MapUtils.getByExpr(data, "words_result.国籍.words"));
        resp.setBirthDate(MapUtils.getByExpr(data, "words_result.出生日期.words"));
        resp.setIssueDate(MapUtils.getByExpr(data, "words_result.初次领证日期.words"));
        resp.setVehicleType(MapUtils.getByExpr(data, "words_result.准驾车型.words"));
        // 电子/归一化模式返回 "有效起始日期"，非归一化返回 "有效期限"
        String startDate = MapUtils.getByExpr(data, "words_result.有效起始日期.words");
        if (startDate == null) {
            startDate = MapUtils.getByExpr(data, "words_result.有效期限.words");
        }
        resp.setStartDate(startDate);

        // 电子/归一化模式返回 "失效日期"，非归一化返回 "至"
        String endDate = MapUtils.getByExpr(data, "words_result.失效日期.words");
        if (endDate == null) {
            endDate = MapUtils.getByExpr(data, "words_result.至.words");
        }
        resp.setEndDate(endDate);
        resp.setAddress(MapUtils.getByExpr(data, "words_result.住址.words"));
        resp.setIssueUnit(MapUtils.getByExpr(data, "words_result.发证单位.words"));

        // 电子驾驶证正页 额外字段
        resp.setAccumulatedPoints(MapUtils.getByExpr(data, "words_result.累积记分.words"));
        resp.setStatus(MapUtils.getByExpr(data, "words_result.状态.words"));
        resp.setArchiveNumber(MapUtils.getByExpr(data, "words_result.档案编号.words"));
        resp.setGenerateTime(MapUtils.getByExpr(data, "words_result.生成时间.words"));
        resp.setCurrentTime(MapUtils.getByExpr(data, "words_result.当前时间.words"));
        resp.setBarcodeNumber(MapUtils.getByExpr(data, "words_result.条形码下编号.words"));

        return resp;
    }

    private RecognizeDriverLicenseBackResp toBackResp(Map<String, Object> data) {
        RecognizeDriverLicenseBackResp resp = new RecognizeDriverLicenseBackResp();
        resp.setName(MapUtils.getByExpr(data, "words_result.姓名.words"));
        resp.setRecord(MapUtils.getByExpr(data, "words_result.记录.words"));
        resp.setCardNumber(MapUtils.getByExpr(data, "words_result.证号.words"));
        resp.setArchiveNumber(MapUtils.getByExpr(data, "words_result.档案编号.words"));
        return resp;
    }

}
