#include "remove_border.h"
#include <math.h>
#include "../common.h"
#include "../image_utilities.h"

using namespace std;

/**
 * 根据边框内边缘获取去除边框所用掩膜
 * 
 * args:
 *     imgshape: 图片宽高信息
 *     shapeType: 印章形状信息
 *     filter_border: 边框内边缘
 * returns:
 *     filterMask: 除边框外的印章掩码
 */
cv::Mat get_filterBorderMask(const cv::Size& imgshape, const string& shapeType, const cv::RotatedRect& filter_border) {
    // 创建全黑图像作为基础
    cv::Mat empty = cv::Mat::zeros(imgshape, CV_8UC1);
    
    if (shapeType == "ellipse" || shapeType == "circle") {
        // 绘制填充的椭圆
        cv::ellipse(empty, filter_border, cv::Scalar(255), -1);
    } else {
        vector<cv::Point> filter_border_box = mrect2box(filter_border);
        vector<vector<cv::Point>> contours;
        contours.push_back(filter_border_box);
        cv::drawContours(empty, contours, -1, cv::Scalar(255), -1);
    }
    
    // 创建掩码：绘制区域为255，其他区域为0
    cv::Mat filterMask;
    cv::compare(empty, 255, filterMask, cv::CMP_EQ);
    
    return filterMask;
}

/**
 * 枚举offsets，找到最合适的边界
 * 
 * args:
 *     img: 图
 *     shapeType: 形状类型
 *     mrect: 一个最小包围矩形
 *     offsets: 平移变换组合
 *     inverse: True以背景点数量最大时为最佳，False以前景点数量最大时为最佳
 *     bg_val: 背景值
 * returns:
 *     best_mrect: 最佳边界，是一个最小包围矩形
 */
cv::RotatedRect _find_bestfit(const cv::Mat& img, const string& shapeType, const cv::RotatedRect& mrect, 
                              const vector<Offset>& offsets, bool inverse, int bg_val) {
    // 如果offsets为空，返回原始mrect
    if (offsets.empty()) {
        return mrect;
    }
    
    // 提取mrect的参数
    cv::Point2f center = mrect.center;
    cv::Size2f wh = mrect.size;
    float angle = mrect.angle;
    
    // 初始化最佳分数和最佳mrect
    float best_score = 0;
    cv::RotatedRect best_mrect = mrect;
    const int color = 255;
    
    // 遍历offsets中的每个变换参数
    for (const auto& offset : offsets) {
        try {
            float tx = offset.tx;
            float ty = offset.ty;
            float ws = offset.ws;
            float hs = offset.hs;
            float ta = offset.ta;
            
            // 创建全黑图像
            cv::Mat empty = cv::Mat::zeros(img.size(), CV_8UC1);
            
            // 计算新的mrect
            cv::Point2f new_center(center.x + tx, center.y + ty);
            // 确保宽高为正数
            float new_width = wh.width + ws;
            float new_height = wh.height + hs;
            if (new_width <= 0 || new_height <= 0) {
                continue;
            }
            cv::Size2f new_wh(new_width, new_height);
            float new_angle = angle + ta;
            cv::RotatedRect new_mrect(new_center, new_wh, new_angle);
            
            // 绘制轮廓并计算内部面积
            float innerArea = 0;
            const int BS = 1; // 线宽，与Python版本保持一致
            if (shapeType == "ellipse" || shapeType == "circle") {
                // 使用线宽 1 绘制边界线，与Python版本保持一致
                cv::ellipse(empty, new_mrect, color, BS);
                innerArea = (new_wh.width * new_wh.height / 4) * M_PI;
            } else {
                vector<cv::Point> new_mrectbox = mrect2box(new_mrect);
                vector<vector<cv::Point>> contours;
                contours.push_back(new_mrectbox);
                cv::drawContours(empty, contours, -1, color, BS);
                innerArea = new_wh.width * new_wh.height;
            }
            
            // 创建轮廓掩码
            cv::Mat cntMask;//得到黑底白色轮廓（线宽1），未进行内部填充
            cv::compare(empty, color, cntMask, cv::CMP_EQ);
            
            // 原始逐像素遍历代码（已注释，保留用于参考）
            // int cntArea = 0;
            // for (int i = 0; i < img.rows; ++i) {
            //     for (int j = 0; j < img.cols; ++j) {
            //         if (cntMask.at<uchar>(i, j)) {
            //             if (!inverse) {
            //                 if (img.at<uchar>(i, j) != bg_val) {
            //                     cntArea++;
            //                 }
            //             } else {
            //                 if (img.at<uchar>(i, j) == bg_val) {
            //                     cntArea++;
            //                 }
            //             }
            //         }
            //     }
            // }
            
            // 使用OpenCV向量化操作计算轮廓区域的像素数（性能优化）
            cv::Mat condMask;//提取二值化图img的背景像素，白底黑字（印章边框+文字）
            if (!inverse) {
                cv::compare(img, bg_val, condMask, cv::CMP_NE);//黑底图走这一句
            } else {
                cv::compare(img, bg_val, condMask, cv::CMP_EQ);//白底图走这一句，把二值图的白色背景提取出来。
            }
            cv::Mat resultMask;
            cv::bitwise_and(cntMask, condMask, resultMask);//对黑底轮廓图和白底二值图进行按位取与运算，得到重合都是白色的掩膜。
            int cntArea = cv::countNonZero(resultMask);//统计掩膜中的非零元素即255，因为初始化阶段已把最佳边框赋值为最小外接矩形，因此不存在会有最佳边框在印章外的情况。
            //通过offset数组设定了一个范围（不太可能无限缩小到内部文字圈）对最小外接矩形进行了不断缩减试探寻求最佳边框，通过找寻背景像素（白）最多的点得到最佳边框。因为文字区域和边框区域为黑，背景为白，在规定的范围内最多白背景的地方为最佳边框。
    
            // 更新最佳分数和最佳mrect
            float score = cntArea;
            if (best_score < score) {
                best_score = score;
                best_mrect = new_mrect;
            }
        } catch (const exception& e) {
            cout << "处理偏移时出错: " << e.what() << endl;
            continue;
        } catch (...) {
            cout << "处理偏移时出错: 未知异常" << endl;
            continue;
        }
    }
    
    return best_mrect;
}

/**
 * 获取去除边框所用掩膜
 * 
 * args:
 *     img: 图
 *     shapeinfo: 形状信息
 *     bg_val: 图片背景色
 * returns:
 *     filterMask: 用来去掉边框的掩膜mask
 *     new_shapeinfo: 新形状信息
 *     inner_border: 边框内边缘
 */
cv::Mat _getFilterMask(const cv::Mat& img, const ShapeInfo& shapeinfo, cv::RotatedRect& inner_border, int bg_val) {
    try {
        // 确保输入是灰度图
        if (img.empty()) {
            cout << "错误: 输入图像为空" << endl;
            return cv::Mat();
        }
        if (img.channels() != 1) {
            cout << "错误: 输入必须是灰度图" << endl;
            return cv::Mat();
        }
        
        // 获取形状类型
        string shapeType = shapeinfo.type;
        if (shapeType.empty()) {
            shapeType = "unknown";
        }
        
        // 对图像进行阈值处理，生成二值图像
        cv::Mat binary;
        // 使用THRESH_BINARY，与Python版本保持一致
        cv::threshold(img, binary, 200, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
        
        // 获取最佳边框
        cv::RotatedRect best_border = shapeinfo.minAreaRect;
        
        // 计算缩进值列表
        const int BIG_SIZE = 365;
        vector<int> indents;
        for (int indent = -18; indent > -44; indent -= 2) {
            indents.push_back(indent);
        }
        
        // 计算k值并扩展indents
        float k = min(best_border.size.width, best_border.size.height) / static_cast<float>(BIG_SIZE);
        if (k > 1) {
            int num_extra = static_cast<int>(ceil(k * 5));
            for (int i = 0; i < num_extra; ++i) {
                indents.push_back(-44 - 4 * i);
            }
        }
        
        // 生成offsets_1
        vector<Offset> offsets_1;
        for (int indent : indents) {
            offsets_1.emplace_back(0, 0, indent, indent, 0);
        }
        
        // 获取边框内边缘
        cv::RotatedRect filter_border = _find_bestfit(binary, shapeType, best_border, offsets_1, true, bg_val);
        
        // 获取去除边框所需要的掩膜
        cv::Mat filterMask = get_filterBorderMask(img.size(), shapeType, filter_border);
        
        // 设置inner_border
        inner_border = filter_border;
        
        return filterMask;
    } catch (const exception& e) {
        cout << "_getFilterMask出错: " << e.what() << endl;
        return cv::Mat();
    } catch (...) {
        cout << "_getFilterMask出错: 未知异常" << endl;
        return cv::Mat();
    }
}

/**
 * 去除边框
 * 
 * args:
 *     img: 图片
 *     shapeinfo: 形状信息
 *     bg_val: 图片的背景颜色，默认是白底黑字, 如果是黑底白字的二值图，请设置bg_val为0
 * returns:
 *     img1: 去掉边框后的图片
 *     mask: 去掉边框所用掩膜
 *     new_shapeinfo: 拟合得更好的形状
 *     inner_border: 边框内边缘
 */
cv::Mat remove_border(const cv::Mat& img, const ShapeInfo& shapeinfo, cv::Mat& mask, ShapeInfo& new_shapeinfo, cv::RotatedRect& inner_border, int bg_val) {
    try {
        // 确保输入是灰度图
        if (img.empty()) {
            cout << "错误: 输入图像为空" << endl;
            return cv::Mat();
        }
        if (img.channels() != 1) {
            cout << "错误: 输入必须是灰度图" << endl;
            return cv::Mat();
        }
        
        // 调用_getFilterMask获取掩膜、新形状信息和边框内边缘
        mask = _getFilterMask(img, shapeinfo, inner_border, bg_val);
        
        // 检查mask是否为空
        if (mask.empty()) {
            cout << "警告: 生成的mask为空，返回原始图像" << endl;
            // 返回原始图像的副本
            new_shapeinfo = shapeinfo;
            return img.clone();
        }
        
        // 确保mask与img尺寸相同
        if (mask.size() != img.size()) {
            cout << "警告: mask尺寸与图像尺寸不同，返回原始图像" << endl;
            new_shapeinfo = shapeinfo;
            return img.clone();
        }
        
        // 复制图片
        cv::Mat img1 = img.clone();
        
        // 应用掩膜：将非mask区域设置为bg_val
        // 原始逐像素遍历代码（已注释，保留用于参考）
        // for (int i = 0; i < img1.rows; ++i) {
        //     for (int j = 0; j < img1.cols; ++j) {
        //         if (!mask.at<uchar>(i, j)) {
        //             img1.at<uchar>(i, j) = static_cast<uchar>(bg_val);
        //         }
        //     }
        // }
        // 使用OpenCV向量化操作（性能优化）
        cv::Mat invertedMask;
        cv::bitwise_not(mask, invertedMask);
        img1.setTo(bg_val, invertedMask);
        
        // 使用计算出的inner_border更新new_shapeinfo
        new_shapeinfo = shapeinfo;
        new_shapeinfo.minAreaRect = inner_border;
        
        return img1;
    } catch (const exception& e) {
        cout << "remove_border出错: " << e.what() << endl;
        // 发生异常时返回原始图像的副本
        new_shapeinfo = shapeinfo;
        return img.clone();
    } catch (...) {
        cout << "remove_border出错: 未知异常" << endl;
        // 发生未知异常时返回原始图像的副本
        new_shapeinfo = shapeinfo;
        return img.clone();
    }
}