package com.example.myapplication.service;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;

import com.tom_roush.pdfbox.android.PDFBoxResourceLoader;
import com.tom_roush.pdfbox.pdmodel.PDDocument;
import com.tom_roush.pdfbox.rendering.PDFRenderer;

import java.io.File;

public class PdfOcrService {
    private static final String TAG = "PdfOcrService";
    public static class Config {
        public int maxPages = -1;
        public float dpiPrimary = 192f;
        public float dpiFallback = 300f;
        public int maxSidePx = 3500;
        public String lang = "chi_sim+eng";
        public int psmPrimary = 4; // 单列
        public int psmAlt = 6;     // 整页
    }

    public static String recognizePdf(Context ctx, String filePath, Config cfg) {
        if (cfg == null) cfg = new Config();
        StringBuilder all = new StringBuilder();
        PDDocument doc = null;
        try {
            try { PDFBoxResourceLoader.init(ctx.getApplicationContext()); } catch (Exception ignored) {}
            doc = PDDocument.load(new File(filePath));
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            int limit = cfg.maxPages <= 0 ? pageCount : Math.min(pageCount, cfg.maxPages);
            for (int i = 0; i < limit; i++) {
                Bitmap bmp = null;
                try {
                    bmp = renderer.renderImageWithDPI(i, cfg.dpiPrimary);
                    // 限制长边
                    int w = bmp.getWidth();
                    int h = bmp.getHeight();
                    int max = Math.max(w, h);
                    if (max > cfg.maxSidePx) {
                        float scale = cfg.maxSidePx * 1f / max;
                        int nw = Math.max(1, (int)(w * scale));
                        int nh = Math.max(1, (int)(h * scale));
                        bmp = Bitmap.createScaledBitmap(bmp, nw, nh, true);
                    }
                    java.util.List<Bitmap> cols = segmentColumns(bmp);
                    String pageText;
                    if (cols != null && cols.size() > 1) {
                        StringBuilder sb = new StringBuilder();
                        for (Bitmap colBmp : cols) {
                            String ca = TesseractService.recognizeBitmap(ctx, colBmp, cfg.lang, cfg.psmPrimary, 1);
                            String cb = TesseractService.recognizeBitmap(ctx, colBmp, cfg.lang, cfg.psmAlt, 1);
                            String ct = (cb != null && (ca == null || cb.length() > ca.length())) ? cb : ca;
                            if (ct != null && !ct.trim().isEmpty()) {
                                if (sb.length() > 0) sb.append('\n');
                                sb.append(ct.trim());
                            }
                            try { if (colBmp != null && !colBmp.isRecycled()) colBmp.recycle(); } catch (Exception ignored) {}
                        }
                        pageText = sb.toString();
                    } else {
                        String a = TesseractService.recognizeBitmap(ctx, bmp, cfg.lang, cfg.psmPrimary, 1);
                        String b = TesseractService.recognizeBitmap(ctx, bmp, cfg.lang, cfg.psmAlt, 1);
                        pageText = (b != null && (a == null || b.length() > a.length())) ? b : a;
                    }
                    // 若文本过短，提升DPI重渲染重试
                    if (pageText == null || pageText.trim().length() < 200) {
                        try { if (bmp != null && !bmp.isRecycled()) bmp.recycle(); } catch (Exception ignored) {}
                        bmp = renderer.renderImageWithDPI(i, cfg.dpiFallback);
                        int w2 = bmp.getWidth(); int h2 = bmp.getHeight(); int max2 = Math.max(w2, h2);
                        if (max2 > cfg.maxSidePx) {
                            float scale2 = cfg.maxSidePx * 1f / max2;
                            int nw2 = Math.max(1, (int)(w2 * scale2));
                            int nh2 = Math.max(1, (int)(h2 * scale2));
                            bmp = Bitmap.createScaledBitmap(bmp, nw2, nh2, true);
                        }
                        String a2 = TesseractService.recognizeBitmap(ctx, bmp, cfg.lang, cfg.psmPrimary, 1);
                        String b2 = TesseractService.recognizeBitmap(ctx, bmp, cfg.lang, cfg.psmAlt, 1);
                        pageText = (b2 != null && (a2 == null || b2.length() > a2.length())) ? b2 : a2;
                    }
                    // 若仍短，再做高对比度二值化并用稀疏文本模式捕捉残缺部分
                    if (pageText == null || pageText.trim().length() < 200) {
                        Bitmap hc = toHighContrast(bmp);
                        String s11 = TesseractService.recognizeBitmap(ctx, hc, cfg.lang, 11, 1); // Sparse text
                        String s06 = TesseractService.recognizeBitmap(ctx, hc, cfg.lang, cfg.psmAlt, 1);
                        String best = (s06 != null && (s11 == null || s06.length() > s11.length())) ? s06 : s11;
                        if (best != null && !best.trim().isEmpty()) {
                            pageText = (pageText == null ? "" : pageText);
                            if (!pageText.isEmpty()) pageText += "\n";
                            pageText += best.trim();
                        }
                        try { if (hc != null && !hc.isRecycled()) hc.recycle(); } catch (Exception ignored) {}
                    }
                    if (pageText != null && !pageText.trim().isEmpty()) {
                        if (all.length() > 0) all.append('\n');
                        all.append(pageText.trim());
                    }
                } catch (Exception e) {
                    Log.w(TAG, "渲染或识别第" + (i+1) + "页失败", e);
                } finally {
                    try { if (bmp != null && !bmp.isRecycled()) bmp.recycle(); } catch (Exception ignored) {}
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "PDF识别失败: " + filePath, e);
        } finally {
            try { if (doc != null) doc.close(); } catch (Exception ignored) {}
        }
        return all.toString();
    }

    private static java.util.List<Bitmap> segmentColumns(Bitmap src) {
        int w = src.getWidth();
        int h = src.getHeight();
        int[] pix = new int[w * h];
        src.getPixels(pix, 0, w, 0, 0, w, h);
        int[] projX = new int[w];
        for (int x = 0; x < w; x++) {
            int cnt = 0;
            for (int y = 0; y < h; y++) {
                int p = pix[y * w + x] & 0xFF;
                if (p < 160) cnt++;
            }
            projX[x] = cnt;
        }
        java.util.List<int[]> ranges = new java.util.ArrayList<>();
        int minCol = Math.max(h / 60, 10);
        int x = 0;
        while (x < w) {
            while (x < w && projX[x] <= minCol) x++;
            if (x >= w) break;
            int start = x;
            while (x < w && projX[x] > minCol) x++;
            int end = x - 1;
            if (end - start + 1 >= w / 10) ranges.add(new int[]{start, end});
        }
        if (ranges.size() <= 1) return java.util.Collections.emptyList();
        java.util.List<Bitmap> cols = new java.util.ArrayList<>();
        for (int[] r : ranges) {
            int cw = Math.max(1, r[1] - r[0] + 1);
            Bitmap col = Bitmap.createBitmap(src, r[0], 0, cw, h);
            cols.add(col);
        }
        return cols;
    }

    private static Bitmap toHighContrast(Bitmap src) {
        try {
            Bitmap out = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Bitmap.Config.ARGB_8888);
            android.graphics.Canvas canvas = new android.graphics.Canvas(out);
            android.graphics.Paint paint = new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG);
            android.graphics.ColorMatrix cm = new android.graphics.ColorMatrix();
            float c = 1.4f;
            cm.set(new float[]{
                    c, 0, 0, 0, 0,
                    0, c, 0, 0, 0,
                    0, 0, c, 0, 0,
                    0, 0, 0, 1, 0
            });
            paint.setColorFilter(new android.graphics.ColorMatrixColorFilter(cm));
            canvas.drawBitmap(src, 0, 0, paint);
            return out;
        } catch (Exception e) {
            return src;
        }
    }
}