package com.codechecker.api.notify;

import com.codechecker.api.model.ApiChangeKind;
import com.codechecker.api.model.EndpointChangeReport;
import com.codechecker.api.model.ParameterChange;
import com.codechecker.common.MarkdownStyles;
import com.codechecker.common.WeComMarkdownSender;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * API 变更通知（路径 / 请求方式 / 参数分类型、分条发送，与类变更通知解耦）。
 */
public class ApiChangeNotifier {
    private final WeComMarkdownSender sender = new WeComMarkdownSender();

    public int sendAll(String webhookUrl, List<EndpointChangeReport> reports,
                       String modifier, String modifyTime, boolean wecomEnabled) {
        if (reports == null || reports.isEmpty()) {
            System.out.println("无 API 变更，不发送通知");
            return 0;
        }
        int sent = 0;
        for (EndpointChangeReport report : reports) {
            String markdown = buildMarkdown(report, modifier, modifyTime);
            if (wecomEnabled) {
                if (sender.send(webhookUrl, markdown)) {
                    sent++;
                    System.out.println("已发送 API 变更通知: " + report.getChangeKind()
                            + " " + report.getHttpMethod() + " " + report.getUri());
                }
            } else {
                sender.logPreview("API 变更 [" + report.getChangeKind() + "]", markdown);
                sent++;
            }
        }
        if (sent > 0) {
            System.out.println("总共发送 " + sent + " 条 API 变更通知");
        }
        return sent;
    }

    public String buildMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
        ApiChangeKind kind = report.getChangeKind();
        if (kind == ApiChangeKind.PATH_CHANGED
                || kind == ApiChangeKind.NEW_ENDPOINT
                || kind == ApiChangeKind.REMOVED_ENDPOINT) {
            return buildPathMarkdown(report, modifier, modifyTime);
        }
        if (kind == ApiChangeKind.METHOD_CHANGED) {
            return buildMethodMarkdown(report, modifier, modifyTime);
        }
        return buildParamMarkdown(report, modifier, modifyTime);
    }

    private String buildPathMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
        String changeLabel;
        switch (report.getChangeKind()) {
            case NEW_ENDPOINT:
                changeLabel = "新增接口";
                break;
            case REMOVED_ENDPOINT:
                changeLabel = "删除接口";
                break;
            default:
                changeLabel = "修改路径";
                break;
        }
        StringBuilder sb = new StringBuilder();
        sb.append("# 【API路径变更通知】").append("\n\n");
        sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning(changeLabel))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("路径",
                MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
        sb.append("\n## 【URI变更详情】").append("\n\n");
        sb.append(MarkdownStyles.quoteKvBold("接口说明", formatEndpointDescription(report))).append("\n");
        appendPathUriLines(sb, report, changeLabel);
        return sb.toString();
    }

    private void appendPathUriLines(StringBuilder sb, EndpointChangeReport report, String changeLabel) {
        if ("新增接口".equals(changeLabel)) {
            sb.append(MarkdownStyles.quoteKvBold("原路径", "`-`")).append("\n");
            sb.append(MarkdownStyles.quoteKvBold("新路径",
                    formatUriWithMethod(report.getHttpMethod(), report.getUri(), true)
                            + "  " + MarkdownStyles.colorInfo("[新增]"))).append("\n");
        } else if ("删除接口".equals(changeLabel)) {
            sb.append(MarkdownStyles.quoteKvBold("原路径",
                    formatUriWithMethod(report.getHttpMethod(), report.getUri(), false)
                            + "  " + MarkdownStyles.colorWarning("[已删除]"))).append("\n");
            sb.append(MarkdownStyles.quoteKvBold("新路径", "`已删除`")).append("\n");
        } else {
            sb.append(MarkdownStyles.quoteKvBold("原路径",
                    formatUriWithMethod(report.getHttpMethod(), report.getOldUri(), false)
                            + "  " + MarkdownStyles.colorWarning("[旧路径]"))).append("\n");
            sb.append(MarkdownStyles.quoteKvBold("新路径",
                    formatUriWithMethod(report.getHttpMethod(), report.getUri(), true)
                            + "  " + MarkdownStyles.colorInfo("[新路径]"))).append("\n");
        }
    }

    private String buildMethodMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
        StringBuilder sb = new StringBuilder();
        sb.append("# 【API请求方式变更通知】").append("\n\n");
        sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning("修改请求方式"))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("路径",
                MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
        sb.append("\n## 【请求方式变更详情】").append("\n\n");
        sb.append(MarkdownStyles.quoteKvBold("接口说明", formatEndpointDescription(report))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("URI", MarkdownStyles.colorInfo(report.getUri()))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("原请求方式",
                MarkdownStyles.colorWarning(report.getOldHttpMethod()))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("新请求方式",
                MarkdownStyles.colorInfo(report.getHttpMethod()) + "  "
                        + MarkdownStyles.colorInfo("[请求方式已变更]"))).append("\n");
        return sb.toString();
    }

    private String buildParamMarkdown(EndpointChangeReport report, String modifier, String modifyTime) {
        StringBuilder sb = new StringBuilder();
        sb.append("# 【API参数变更通知】").append("\n\n");
        sb.append(MarkdownStyles.quoteKvBold("修改人", MarkdownStyles.colorComment(modifier))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("时间", MarkdownStyles.colorComment(modifyTime))).append("\n");
        //sb.append(MarkdownStyles.quoteKvBold("变更类型", MarkdownStyles.colorWarning("修改参数"))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("URI",
                MarkdownStyles.colorInfo(report.getHttpMethod()) + " "
                        + MarkdownStyles.inlineCode(report.getUri()))).append("\n");
        sb.append(MarkdownStyles.quoteKvBold("路径",
                MarkdownStyles.colorInfo(MarkdownStyles.safe(report.getSourceFile())))).append("\n");
        sb.append("\n## 【接口参数变动详情】").append("\n\n");
        appendParameterDetails(sb, report);
        return sb.toString();
    }

    private void appendParameterDetails(StringBuilder sb, EndpointChangeReport report) {
        List<ParameterChange> bodyChanges = new ArrayList<>();
        List<ParameterChange> regularChanges = new ArrayList<>();
        for (ParameterChange change : report.getParameterChanges()) {
            if (change.isBodyField()) {
                bodyChanges.add(change);
            } else {
                regularChanges.add(change);
            }
        }
        if (!bodyChanges.isEmpty()) {
            sb.append("**类对象变更（含嵌套对象字段）**").append("\n\n");
            appendBodyGroups(sb, bodyChanges);
            sb.append("\n");
        }
        if (!regularChanges.isEmpty()) {
            sb.append("**普通参数变更**").append("\n\n");
            sb.append(MarkdownStyles.quoteLine("**共 "
                    + MarkdownStyles.colorWarning(String.valueOf(regularChanges.size()))
                    + " 项变更**")).append("\n\n");
            for (ParameterChange change : regularChanges) {
                sb.append(formatParameterLine(change)).append("\n\n");
            }
        }
        if (bodyChanges.isEmpty() && regularChanges.isEmpty()) {
            sb.append(MarkdownStyles.quoteLine(MarkdownStyles.colorComment("无"))).append("\n");
        }
    }

    private void appendBodyGroups(StringBuilder sb, List<ParameterChange> bodyChanges) {
        Map<String, List<ParameterChange>> groups = new LinkedHashMap<>();
        for (ParameterChange change : bodyChanges) {
            String key = change.getParentDto() == null || change.getParentDto().isBlank()
                    ? (change.getBodyParamName() == null ? "body" : change.getBodyParamName())
                    : change.getParentDto();
            groups.computeIfAbsent(key, k -> new ArrayList<>()).add(change);
        }
        int total = bodyChanges.size();
        sb.append(MarkdownStyles.quoteLine("**共 "
                + MarkdownStyles.colorWarning(String.valueOf(groups.size()))
                + " 个类对象 · "
                + MarkdownStyles.colorWarning(String.valueOf(total))
                + " 项变更**")).append("\n\n");
        for (List<ParameterChange> group : groups.values()) {
            ParameterChange first = group.get(0);
            if (first.getParentDto() != null && !first.getParentDto().isBlank()) {
                sb.append("**").append(MarkdownStyles.inlineCode(first.getParentDto())).append("**");
            } else if (first.getBodyParamName() != null && !first.getBodyParamName().isBlank()) {
                sb.append("**").append(MarkdownStyles.inlineCode(first.getBodyParamName())).append("**");
            }
            sb.append("\n\n");
            for (ParameterChange change : group) {
                sb.append(formatParameterLine(change)).append("\n\n");
            }
        }
    }

    private String formatParameterLine(ParameterChange change) {
        String tag;
        switch (change.getChangeType()) {
            case ADDED:
                tag = MarkdownStyles.colorInfo("[新增]");
                break;
            case REMOVED:
                tag = MarkdownStyles.colorWarning("[删除]");
                break;
            case RENAMED:
                tag = MarkdownStyles.colorWarning("[重命名]");
                break;
            case MODIFIED:
                tag = MarkdownStyles.colorWarning("[类型变更]");
                break;
            default:
                tag = MarkdownStyles.colorWarning("[修改]");
                break;
        }
        String name = MarkdownStyles.inlineCode(MarkdownStyles.safe(change.displayName()));
        String desc = change.getDescription() == null || change.getDescription().isBlank()
                ? MarkdownStyles.colorComment("（无说明）")
                : MarkdownStyles.colorComment(change.getDescription());
        StringBuilder line = new StringBuilder();
        if (change.getChangeType() == ParameterChange.ChangeType.RENAMED) {
            line.append(tag).append("  ")
                    .append(MarkdownStyles.colorComment(MarkdownStyles.safe(change.getOldName()))).append(" → ")
                    .append(MarkdownStyles.colorInfo(MarkdownStyles.safe(change.getParamName())))
                    .append("  说明:  ").append(desc);
        } else {
            line.append(tag).append("  ").append(name).append("  说明:  ").append(desc);
        }
        appendParameterType(line, change);
        return MarkdownStyles.quoteLine(line.toString());
    }

    private void appendParameterType(StringBuilder line, ParameterChange change) {
        String typePart = resolveTypePart(change);
        if (!typePart.isBlank()) {
            line.append("  类型:  ").append(typePart);
        }
    }

    private String formatUriWithMethod(String httpMethod, String uri, boolean isNew) {
        String path = MarkdownStyles.inlineCode(MarkdownStyles.safe(uri));
        if (httpMethod == null || httpMethod.isBlank()) {
            return path;
        }
        String methodPart = isNew
                ? MarkdownStyles.colorInfo(httpMethod.toUpperCase())
                : MarkdownStyles.colorWarning(httpMethod.toUpperCase());
        return methodPart + "  " + path;
    }

    private String formatEndpointDescription(EndpointChangeReport report) {
        String desc = report.getEndpointDescription();
        if (desc == null || desc.isBlank()) {
            return MarkdownStyles.colorComment("（无说明）");
        }
        return MarkdownStyles.colorComment(MarkdownStyles.safe(desc));
    }

    private String resolveTypePart(ParameterChange change) {
        if (change.getChangeType() == ParameterChange.ChangeType.MODIFIED
                && change.getDetail() != null && !change.getDetail().isBlank()) {
            return MarkdownStyles.formatTypeChange(change.getDetail());
        }
        if (change.getParamType() != null && !change.getParamType().isBlank()) {
            boolean isNew = change.getChangeType() == ParameterChange.ChangeType.ADDED
                    || change.getChangeType() == ParameterChange.ChangeType.RENAMED;
            return MarkdownStyles.formatSingleType(change.getParamType(), isNew);
        }
        return "";
    }
}
