package org.dromara.main.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.domain.R;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.main.domain.bo.MainBackCategoryBo;
import org.dromara.main.domain.bo.MainBackClauseBo;
import org.dromara.main.domain.bo.PortalCheckOrderCreateBo;
import org.dromara.main.domain.vo.MainBackCategoryVo;
import org.dromara.main.domain.vo.MainBackClauseVo;
import org.dromara.main.domain.vo.MainBackOrderCandidateVo;
import org.dromara.main.domain.vo.MainBackOrderVo;
import org.dromara.main.service.IMainBackCategoryService;
import org.dromara.main.service.IMainBackClauseService;
import org.dromara.main.service.IMainBackOrderService;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.service.ISysDictTypeService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 门户背调公开接口
 */
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping("/portal/check")
public class PortalCheckController extends BaseController {

    private static final Map<String, String> CLAUSE_TYPE_CODE_MAP = Map.of(
        "身份风险", "1",
        "职业风险", "2",
        "能力评估", "3"
    );

    private final IMainBackCategoryService mainBackCategoryService;
    private final IMainBackClauseService mainBackClauseService;
    private final IMainBackOrderService mainBackOrderService;
    private final ISysDictTypeService dictTypeService;

    @GetMapping("/category/top3")
    public R<List<CategoryWithClausesVo>> getTop3CategoriesWithClauses() {
        MainBackCategoryBo categoryBo = new MainBackCategoryBo();
        categoryBo.setStatus("1");

        List<MainBackCategoryVo> categories = new ArrayList<>(mainBackCategoryService.queryList(categoryBo));
        categories.sort(Comparator.comparing(MainBackCategoryVo::getId));
        if (categories.size() > 3) {
            categories = categories.subList(0, 3);
        }

        List<CategoryWithClausesVo> result = new ArrayList<>(categories.size());
        for (MainBackCategoryVo category : categories) {
            MainBackClauseBo clauseBo = new MainBackClauseBo();
            clauseBo.setCategoryId(category.getId());
            clauseBo.setStatus("1");
            List<MainBackClauseVo> clauses = mainBackClauseService.queryList(clauseBo);

            List<PortalCheckClauseVo> clauseVos = clauses.stream()
                .map(clause -> toPortalClauseVo(clause, category.getName()))
                .toList();

            result.add(new CategoryWithClausesVo(toPortalCategoryVo(category), clauseVos));
        }
        return R.ok(result);
    }

    @GetMapping("/clauses/grouped")
    public R<Map<String, List<PortalCheckClauseVo>>> getAllClausesGrouped() {
        MainBackClauseBo bo = new MainBackClauseBo();
        bo.setStatus("1");
        List<MainBackClauseVo> clauses = mainBackClauseService.queryList(bo);

        MainBackCategoryBo categoryBo = new MainBackCategoryBo();
        categoryBo.setStatus("1");
        Map<Long, String> categoryNameMap = new LinkedHashMap<>();
        for (MainBackCategoryVo category : mainBackCategoryService.queryList(categoryBo)) {
            categoryNameMap.put(category.getId(), category.getName());
        }

        Map<String, List<PortalCheckClauseVo>> grouped = new LinkedHashMap<>();
        for (MainBackClauseVo clause : clauses) {
            PortalCheckClauseVo clauseVo = toPortalClauseVo(clause, categoryNameMap.get(clause.getCategoryId()));
            String clauseType = clauseVo.getClauseType();
            grouped.computeIfAbsent(clauseType == null || clauseType.isBlank() ? "0" : clauseType, key -> new ArrayList<>())
                .add(clauseVo);
        }
        return R.ok(grouped);
    }

    @GetMapping("/dict/{dictType}")
    public R<List<SysDictDataVo>> getPublicDict(@PathVariable String dictType) {
        List<String> allowedTypes = Arrays.asList(
            "candidate_id_type",
            "main_clause_type",
            "check_process_status",
            "withdraw_account_type",
            "order_status"
        );
        if (!allowedTypes.contains(dictType)) {
            return R.fail("不允许查询该字典类型");
        }

        String actualType = "main_clause_type".equals(dictType) ? "sys_clause_type" : dictType;
        List<SysDictDataVo> data = dictTypeService.selectDictDataByType(actualType);
        if (data == null) {
            data = new ArrayList<>();
        }
        if ("main_clause_type".equals(dictType)) {
            data = data.stream().map(this::toPortalClauseTypeDict).toList();
        }
        return R.ok(data);
    }

    @GetMapping("/order/list")
    public R<List<MainBackOrderVo>> getMyOrders() {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        return R.ok(mainBackOrderService.queryPortalListByTenantId(tenantId));
    }

    @GetMapping("/order/detail")
    public R<MainBackOrderVo> getOrderDetail(@RequestParam String orderNo) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        MainBackOrderVo detail = mainBackOrderService.queryPortalDetail(orderNo, tenantId);
        if (detail == null) {
            return R.fail("订单不存在");
        }
        return R.ok(detail);
    }

    @PostMapping("/order/candidate/{recordId}/authorize/confirm")
    public R<MainBackOrderCandidateVo> confirmPortalCandidateAuthorization(@PathVariable Long recordId) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        return R.ok(mainBackOrderService.confirmPortalCandidateAuthorization(recordId, tenantId));
    }

    @GetMapping("/order/candidate/{recordId}/report")
    public R<String> generatePortalCandidateReport(@PathVariable Long recordId) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        return R.ok("操作成功", mainBackOrderService.generatePortalCandidateReport(recordId, tenantId));
    }

    @GetMapping("/order/candidate/{recordId}/report/download")
    public void downloadPortalCandidateReport(@PathVariable Long recordId, HttpServletResponse response) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            throw new ServiceException("未登录或token已失效");
        }
        mainBackOrderService.downloadPortalCandidateReport(recordId, tenantId, response);
    }

    @PostMapping("/order/create")
    public R<MainBackOrderVo> createOrder(@Validated @RequestBody PortalCheckOrderCreateBo bo) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        return R.ok(mainBackOrderService.createPortalOrder(tenantId, bo));
    }

    @PostMapping("/order/{orderId}/payByBalance")
    public R<Void> payByBalance(@PathVariable Long orderId) {
        String tenantId = LoginHelper.getTenantId();
        if (tenantId == null || tenantId.isBlank()) {
            return R.fail("未登录或token已失效");
        }
        mainBackOrderService.payOrderByBalance(orderId, tenantId);
        return R.ok();
    }

    private PortalCheckCategoryVo toPortalCategoryVo(MainBackCategoryVo category) {
        PortalCheckCategoryVo vo = new PortalCheckCategoryVo();
        vo.setId(category.getId());
        vo.setCategoryName(category.getName());
        vo.setCategoryPrice(category.getPrice());
        vo.setCreateTime(category.getCreateTime() == null ? null :
            java.util.Date.from(category.getCreateTime().atZone(ZoneId.systemDefault()).toInstant()));
        vo.setRemark(category.getRemark());
        return vo;
    }

    private PortalCheckClauseVo toPortalClauseVo(MainBackClauseVo clause, String categoryName) {
        PortalCheckClauseVo vo = new PortalCheckClauseVo();
        vo.setId(clause.getId());
        vo.setCategoryId(clause.getCategoryId());
        vo.setCategoryName(categoryName);
        vo.setClauseName(clause.getName());
        vo.setClauseType(normalizeClauseType(clause.getType()));
        vo.setClauseSetting("0");
        vo.setClauseContent(clause.getDescription());
        vo.setClausePrice(clause.getPrice());
        vo.setIsFree(0);
        vo.setStatus(parseIntOrDefault(clause.getStatus(), 1));
        vo.setCreateTime(clause.getCreateTime());
        vo.setRemark(clause.getRemark());
        return vo;
    }

    private String normalizeClauseType(String rawType) {
        if (rawType == null || rawType.isBlank()) {
            return "0";
        }
        if (rawType.chars().allMatch(Character::isDigit)) {
            return rawType;
        }
        return CLAUSE_TYPE_CODE_MAP.getOrDefault(rawType, rawType);
    }

    private int parseIntOrDefault(String value, int defaultValue) {
        if (value == null || value.isBlank()) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException ignored) {
            return defaultValue;
        }
    }

    private SysDictDataVo toPortalClauseTypeDict(SysDictDataVo source) {
        SysDictDataVo target = new SysDictDataVo();
        target.setDictCode(source.getDictCode());
        target.setDictSort(source.getDictSort());
        target.setDictLabel(source.getDictLabel());
        target.setDictValue(normalizeClauseType(source.getDictValue()));
        target.setDictType("main_clause_type");
        target.setCssClass(source.getCssClass());
        target.setListClass(source.getListClass());
        target.setIsDefault(source.getIsDefault());
        target.setRemark(source.getRemark());
        return target;
    }

    @Data
    private static class PortalCheckCategoryVo {
        private Long id;
        private String categoryName;
        private BigDecimal categoryPrice;
        private java.util.Date createTime;
        private String remark;
    }

    @Data
    private static class PortalCheckClauseVo {
        private Long id;
        private Long categoryId;
        private String categoryName;
        private String clauseName;
        private String clauseType;
        private String clauseSetting;
        private String clauseContent;
        private BigDecimal clausePrice;
        private Integer isFree;
        private Integer status;
        private java.util.Date createTime;
        private String remark;
    }

    @Data
    @AllArgsConstructor
    private static class CategoryWithClausesVo {
        private PortalCheckCategoryVo category;
        private List<PortalCheckClauseVo> clauses;
    }
}
