package com.heyu.api.controller.car;

import com.heyu.api.baidu.request.financial.BTrainTicketRequest;
import com.heyu.api.controller.BaseController;
import com.heyu.api.data.annotation.EbAuthentication;
import com.heyu.api.data.annotation.NotIntercept;
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.TrainTicketRecognizeRequest;
import com.heyu.api.resp.car.RecognizeTrainTicketResp;
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.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * https://console.bce.baidu.com/support/#/api?product=AI&project=文字识别&parent=财务票据OCR&api=rest%2F2.0%2Focr%2Fv1%2Ftrain_ticket&method=post
 *
 * 火车票识别（百度OCR）
 *
 * 支持识别各类火车票的全部字段，包括车票号码、乘车日期时间、出发站、到达站、车次号、席别、座位号、
 * 乘车人姓名、票价等信息。
 */
@Slf4j
@RestController
@RequestMapping("/train/ticket")
@NotIntercept
@SuppressWarnings("unchecked")
public class RecognizeTrainTicketController extends BaseController {

    private static final String TRAIN_TICKET_URI = "/rest/2.0/ocr/v1/train_ticket";

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

        long t1 = System.currentTimeMillis();
        BTrainTicketRequest 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(TRAIN_TICKET_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("火车票识别失败");
        }

        Map<String, Object> wordsResult = MapUtils.getByExpr(data, "words_result");
        if (wordsResult == null) {
            log.info("火车票识别-未识别到火车票信息, 耗时:{}ms", System.currentTimeMillis() - start);
            return R.error("未识别到火车票信息");
        }

        long t3 = System.currentTimeMillis();
        RecognizeTrainTicketResp resp = toResp(wordsResult);
        log.info("火车票识别-结果映射耗时:{}ms", System.currentTimeMillis() - t3);

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

    private BTrainTicketRequest toBaiduRequest(TrainTicketRecognizeRequest request) {
        BTrainTicketRequest bRequest = new BTrainTicketRequest();
        if (request == null) {
            return bRequest;
        }
        if (StringUtils.isNotBlank(request.getImageBase64())) {
            bRequest.setImageBase64(encodeParam(request.getImageBase64()));
        }
        if (StringUtils.isNotBlank(request.getImageUrl())) {
            bRequest.setImageUrl(encodeParam(request.getImageUrl()));
        }
        return bRequest;
    }

    private String checkRequest(BTrainTicketRequest request) {
        if (!hasImage(request)) {
            return "imageUrl和imageBase64不能同时为空";
        }
        return null;
    }

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

    private String getContent(BTrainTicketRequest request) {
        return getImageContent(request).toString();
    }

    private StringBuffer getImageContent(BTrainTicketRequest 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 RecognizeTrainTicketResp toResp(Map<String, Object> words) {
        RecognizeTrainTicketResp resp = new RecognizeTrainTicketResp();

        resp.setName((String) words.get("name"));
        resp.setNumber((String) words.get("train_num"));
        resp.setDepartureStation((String) words.get("starting_station"));
        resp.setDestination((String) words.get("destination_station"));
        resp.setLevel((String) words.get("seat_category"));
        resp.setSeat((String) words.get("seat_num"));

        // 日期和时间合并：百度返回独立date和time字段，合并为"2017年08月05日 22:09开"格式
        String date = (String) words.get("date");
        String time = (String) words.get("time");
        StringBuilder dateTime = new StringBuilder();
        if (StringUtils.isNotBlank(date)) {
            dateTime.append(date);
        }
        if (StringUtils.isNotBlank(time)) {
            if (dateTime.length() > 0) {
                dateTime.append(" ");
            }
            dateTime.append(time);
        }
        resp.setDate(dateTime.length() > 0 ? dateTime.toString() : null);

        // 票价：百度返回字符串，转为Float
        String ticketRates = (String) words.get("ticket_rates");
        if (StringUtils.isNotBlank(ticketRates)) {
            try {
                resp.setPrice(Float.parseFloat(ticketRates));
            } catch (NumberFormatException e) {
                log.warn("票价解析失败:{}", ticketRates);
                resp.setPrice(null);
            }
        }

        return resp;
    }

    private String encodeParam(String value) {
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("URL编码失败:{}", value, e);
            return value;
        }
    }
}
