package com.zhengmeng.ocrplatform.fill;

import com.zhengmeng.ocrplatform.extraction.OcrKeyValueEntity;
import com.zhengmeng.ocrplatform.extraction.OcrKeyValueRepository;
import com.zhengmeng.ocrplatform.form.FormFieldMappingEntity;
import com.zhengmeng.ocrplatform.form.FormFieldMappingRepository;
import com.zhengmeng.ocrplatform.form.FormTemplateRecord;
import com.zhengmeng.ocrplatform.form.FormTemplateService;
import com.zhengmeng.ocrplatform.task.OcrTaskEntity;
import com.zhengmeng.ocrplatform.task.OcrTaskRepository;
import com.zhengmeng.ocrplatform.task.TaskNotFoundException;
import com.zhengmeng.ocrplatform.task.TaskResultRetentionService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class FillDataService {
    private final OcrTaskRepository taskRepository;
    private final OcrKeyValueRepository keyValueRepository;
    private final FormTemplateService formTemplateService;
    private final FormFieldMappingRepository mappingRepository;
    private final TaskResultRetentionService retentionService;

    public FillDataService(OcrTaskRepository taskRepository,
                          OcrKeyValueRepository keyValueRepository,
                          FormTemplateService formTemplateService,
                          FormFieldMappingRepository mappingRepository,
                          TaskResultRetentionService retentionService) {
        this.taskRepository = taskRepository;
        this.keyValueRepository = keyValueRepository;
        this.formTemplateService = formTemplateService;
        this.mappingRepository = mappingRepository;
        this.retentionService = retentionService;
    }

    public FillDataPayload buildForm3Payload(String taskId, String templateCode) {
        return buildForm3Payload(taskId, templateCode, null);
    }

    public FillDataPayload buildForm3Payload(String taskId, String templateCode, String clientCode) {
        OcrTaskEntity task = taskRepository.findByTaskId(taskId)
                .orElseThrow(() -> new TaskNotFoundException(taskId));
        if (clientCode != null && !clientCode.isBlank() && !clientCode.equals(task.getClientCode())) {
            throw new com.zhengmeng.ocrplatform.task.TaskAccessDeniedException(taskId, clientCode);
        }
        retentionService.ensureReadable(task, clientCode);

        FormTemplateRecord template = formTemplateService.resolveTemplateForTask(taskId, templateCode);

        List<FormFieldMappingEntity> mappings = mappingRepository.findByTemplateCodeOrderByIdAsc(template.templateCode());
        Integer latestRunNo = keyValueRepository.findMaxRunNoByTaskId(taskId);
        List<OcrKeyValueEntity> latestRunKeyValues = latestRunNo == null
                ? List.of()
                : keyValueRepository.findByTaskIdAndRunNoOrderByIdAsc(taskId, latestRunNo);

        Map<String, OcrKeyValueEntity> keyValueByField = latestRunKeyValues
                .stream()
                .collect(Collectors.toMap(OcrKeyValueEntity::getFieldKey,
                        entity -> entity,
                        (existing, replacement) -> existing,
                        LinkedHashMap::new));

        List<String> warnings = new ArrayList<>();

        Map<String, String> nameModal = new LinkedHashMap<>();
        Map<String, String> fieldIdModal = new LinkedHashMap<>();
        Map<String, String> canonicalModal = new LinkedHashMap<>();
        List<FillDataFieldItem> fieldItems = new ArrayList<>();

        for (FormFieldMappingEntity mapping : mappings) {
            OcrKeyValueEntity kv = keyValueByField.get(mapping.getOcrFieldKey());
            String value = kv == null ? "" : kvValue(kv);
            if (value.isBlank()) {
                warnings.add("未命中抽取字段: " + mapping.getOcrFieldKey());
            }

            String inputName = normalizeInputName(mapping.getFormInputName());
            String canonicalKey = extractCanonicalKey(inputName);

            nameModal.put(inputName, value);
            fieldIdModal.put(mapping.getFormFieldKey(), value);
            canonicalModal.put(canonicalKey, value);

            fieldItems.add(new FillDataFieldItem(
                    mapping.getFormFieldKey(),
                    inputName,
                    canonicalKey,
                    mapping.getFieldLabel(),
                    value,
                    mapping.getValueType(),
                    kv == null ? null : kv.getPageNo(),
                    formatConfidence(kv == null ? null : kv.getConfidence()),
                    kv == null ? "EMPTY" : kv.getReviewStatus(),
                    mapping.getOcrFieldKey()
            ));
        }

        return new FillDataPayload(
                task.getTaskId(),
                task.getTaskId(),
                template.templateCode(),
                task.getStatus().name(),
                nameModal,
                fieldIdModal,
                canonicalModal,
                fieldItems,
                warnings
        );
    }

    private String kvValue(OcrKeyValueEntity entity) {
        return (entity.getNormalizedValue() == null || entity.getNormalizedValue().isBlank())
                ? safe(entity.getValueText())
                : entity.getNormalizedValue();
    }

    private String safe(String value) {
        return value == null ? "" : value;
    }

    private String normalizeInputName(String inputName) {
        if (inputName == null || inputName.isBlank()) {
            return "";
        }
        return inputName.trim();
    }

    private String extractCanonicalKey(String inputName) {
        int idx = inputName.indexOf('[');
        if (idx <= 0) {
            return inputName;
        }
        return inputName.substring(0, idx);
    }

    private String formatConfidence(BigDecimal confidence) {
        if (confidence == null) {
            return "";
        }
        return confidence.setScale(4, RoundingMode.HALF_UP).toPlainString();
    }
}
