package com.sz.admin.monitor.utils;

import org.bytedeco.javacpp.indexer.FloatIndexer;
import org.bytedeco.javacpp.indexer.IntIndexer;
import org.bytedeco.javacpp.indexer.UByteIndexer;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.MatVector;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_core.TermCriteria;

import java.util.HashMap;
import java.util.Map;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

public class BackgroundDetector {

    // ===============================
    // 统一的对外返回结果类 (与 V3/V4 一致)
    // ===============================
    public static class DetectResult {
        public String type;
        public String value;
        public String code;
        public String desc;
        public double conf;
        public double score;
        public double ratio;

        public DetectResult(String type, String value, String code, String desc, double conf, double score, double ratio) {
            this.type = type;
            this.value = value;
            this.code = code;
            this.desc = desc;
            this.conf = conf;
            this.score = score;
            this.ratio = ratio;
        }

        @Override
        public String toString() {
            return String.format("Result{type='%s', value='%s', code='%s', desc='%s', conf=%.1f, score=%.2f, ratio=%.2f}",
                    type, value, code, desc, conf, score, ratio);
        }
    }

    // ===============================
    // 内部使用的算法基础数据封装
    // ===============================
    private static class InternalDetectionResult {
        public boolean hasLargeBackground;
        public double continuousBackgroundRatio;
        public double totalMaxLabelRatio;
        public Map<String, Integer> mainBackgroundColor;
    }

    // ===============================
    // 对外暴露的公共访问方法 (默认参数)
    // ===============================
    public static DetectResult detectBackground(String imagePath) {
        // 默认参数设定
        int nClusters = 3;
        double areaThreshold = 0.55;
        int kernelSize = 5;
        boolean useGray = false;
        double clusterThreshold = 0.55;
        return detectBackground(imagePath, nClusters, areaThreshold, kernelSize, useGray, clusterThreshold);
    }

    // ===============================
    // 对外暴露的公共访问方法 (支持自定义参数)
    // ===============================
    public static DetectResult detectBackground(String imagePath, int nClusters, double areaThreshold,
                                                int kernelSize, boolean useGray, double clusterThreshold) {
        Mat img = imread(imagePath);
        if (img == null || img.empty()) {
            throw new IllegalArgumentException("无法读取图片或图片不存在: " + imagePath);
        }

        try {
            // 调用核心算法
            InternalDetectionResult internalResult = detectLargeContinuousBackground(
                    img, nClusters, areaThreshold, kernelSize, useGray, clusterThreshold);

            // 将连续背景占比转化为 0-100 的 score 形式便于理解
            double score = internalResult.continuousBackgroundRatio * 100.0;

            // 拼接详细描述信息
            String desc = String.format("连续背景占比:%.2f%%, 最大聚类占比:%.2f%%, 主颜色:%s",
                    score,
                    internalResult.totalMaxLabelRatio * 100.0,
                    internalResult.mainBackgroundColor.toString());

            String detectTypeKey = "background";

            if (internalResult.hasLargeBackground) {
                // value="1" 表示检测出大片连续背景 (异常状态)，code 给 4001
                return new DetectResult(detectTypeKey, "1", "4001", "大片连续/纯色背景 [" + desc + "]", 1.0, score, 0.0);
            } else {
                // value="0" 表示正常图片
                return new DetectResult(detectTypeKey, "0", "2000", "正常背景 [" + desc + "]", 1.0, score, 0.0);
            }
        } finally {
            // 确保释放读取的图片内存
            img.close();
        }
    }


    // ===============================
    // 核心算法实现：基于颜色聚类+连通域
    // ===============================
    private static InternalDetectionResult detectLargeContinuousBackground(
            Mat img, int nClusters, double areaThreshold, int kernelSize, boolean useGray, double clusterThreshold) {

        int h = img.rows();
        int w = img.cols();
        int totalPixels = h * w;

        Mat processed = new Mat();
        Mat reshaped32f = new Mat();

        // 1. 预处理
        if (useGray) {
            cvtColor(img, processed, COLOR_BGR2GRAY);
            Mat kernel = getStructuringElement(MORPH_RECT, new Size(kernelSize, kernelSize));
            morphologyEx(processed, processed, MORPH_OPEN, kernel);
        } else {
            GaussianBlur(img, processed, new Size(3, 3), 0);
        }

        // 重塑为K-Means输入格式
        Mat reshaped = processed.reshape(1, totalPixels);
        reshaped.convertTo(reshaped32f, CV_32F);

        // 2. K-Means颜色聚类
        Mat labels = new Mat();
        Mat centers = new Mat();
        TermCriteria criteria = new TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
        kmeans(reshaped32f, nClusters, labels, criteria, 10, KMEANS_PP_CENTERS, centers);

        // 3. 统计最大类
        int[] labelCounts = new int[nClusters];
        IntIndexer labelIndexer = labels.createIndexer();
        for (int i = 0; i < totalPixels; i++) {
            int label = labelIndexer.get(i, 0);
            labelCounts[label]++;
        }

        int maxLabel = 0;
        int maxCount = 0;
        for (int i = 0; i < nClusters; i++) {
            if (labelCounts[i] > maxCount) {
                maxCount = labelCounts[i];
                maxLabel = i;
            }
        }
        double maxLabelRatio = (double) maxCount / totalPixels;

        // 4. 生成最大类的掩码并分析连通域
        Mat mask = new Mat(h, w, CV_8UC1);
        UByteIndexer maskIndexer = mask.createIndexer();
        int pixelIdx = 0;
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                int label = labelIndexer.get(pixelIdx++, 0);
                maskIndexer.put(y, x, label == maxLabel ? 255 : 0);
            }
        }

        MatVector contours = new MatVector();
        Mat hierarchy = new Mat();
        findContours(mask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

        double largestContourArea = 0;
        for (int i = 0; i < contours.size(); i++) {
            double area = contourArea(contours.get(i));
            if (area > largestContourArea) {
                largestContourArea = area;
            }
        }

        double continuousBackgroundRatio = largestContourArea / totalPixels;
        boolean hasLargeBackground = (continuousBackgroundRatio >= areaThreshold) && (maxLabelRatio >= clusterThreshold);

        // 5. 提取主颜色
        FloatIndexer centersIndexer = centers.createIndexer();
        Map<String, Integer> mainColor = new HashMap<>();
        if (useGray) {
            mainColor.put("gray", (int) centersIndexer.get(maxLabel, 0));
        } else {
            mainColor.put("B", (int) centersIndexer.get(maxLabel, 0));
            mainColor.put("G", (int) centersIndexer.get(maxLabel, 1));
            mainColor.put("R", (int) centersIndexer.get(maxLabel, 2));
        }

        // 6. 构造内部返回结果
        InternalDetectionResult result = new InternalDetectionResult();
        result.hasLargeBackground = hasLargeBackground;
        result.continuousBackgroundRatio = continuousBackgroundRatio;
        result.totalMaxLabelRatio = maxLabelRatio;
        result.mainBackgroundColor = mainColor;

        // 释放临时对象
        processed.close();
        reshaped32f.close();
        reshaped.close();
        labels.close();
        centers.close();
        mask.close();
        hierarchy.close();

        return result;
    }

    // ===============================
    // 测试入口
    // ===============================
    public static void main(String[] args) {
        // 替换为你的真实测试图片路径
        String path = "D:\\work\\ceshi\\bai.jpg";

        try {
            System.out.println("===== 开始检测 =====");
            // 直接调用极简的封装方法
            DetectResult result = detectBackground(path);
            System.out.println(result.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}