"""批量处理服务：扫描 data/input/ 下图片，串行跑完整 OCR → 采购单流程。

- 不合并（每张图片单独出一个 result）
- 默认串行（避免百度 OCR 限流）
- 返回 dict 汇总：total / success / failed / results[]
"""
from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional

from app.config.settings import ConfigManager
from app.core.utils.log_utils import get_logger
from .ocr_service import OCRService
from .order_service import OrderService

logger = get_logger(__name__)


IMAGE_EXTS = {'.png', '.jpg', '.jpeg', '.bmp', '.webp', '.tif', '.tiff'}


class BatchService:
    """批量处理服务。"""

    def __init__(self, config: Optional[ConfigManager] = None, missing_barcodes_cb: Optional[Callable[[List[str]], None]] = None):
        self.config = config or ConfigManager()
        self.missing_barcodes_cb = missing_barcodes_cb
        self.ocr_service = OCRService(self.config)
        self.order_service = OrderService(self.config, missing_barcodes_cb=self.missing_barcodes_cb)
        self._input_folder = self.config.get_path(
            'Paths', 'input_folder', fallback='data/input', create=True
        )

    @property
    def input_folder(self) -> str:
        return self._input_folder

    def list_input_images(self) -> List[str]:
        """列出 data/input/ 下所有待处理图片（按 mtime 升序，先入先出）。"""
        if not os.path.isdir(self._input_folder):
            return []
        files = []
        for name in os.listdir(self._input_folder):
            p = os.path.join(self._input_folder, name)
            if not os.path.isfile(p):
                continue
            ext = os.path.splitext(name)[1].lower()
            if ext in IMAGE_EXTS:
                files.append(p)
        files.sort(key=lambda p: os.path.getmtime(p))
        return files

    def process_all_inputs(
        self,
        progress_cb: Optional[Callable[[int, int, dict], None]] = None,
    ) -> Dict[str, Any]:
        """批量处理 data/input/ 下全部图片。

        Args:
            progress_cb: 可选回调 fn(done_count, total_count, latest_result_dict)

        Returns:
            {
                'total': int,
                'success': int,
                'failed': int,
                'results': [
                    {
                        'image': str,
                        'hash': str,
                        'status': 'success' | 'failed',
                        'supplier': str,
                        'bill_date': str,
                        'total_amount': float,
                        'result_file': str | None,
                        'error': str | None,
                    },
                    ...
                ]
            }
        """
        images = self.list_input_images()
        total = len(images)
        results: List[Dict[str, Any]] = []

        if total == 0:
            logger.info("data/input/ 下无待处理图片")
            return {'total': 0, 'success': 0, 'failed': 0, 'results': []}

        logger.info(f"批量处理开始: 共 {total} 张图片")
        success = 0
        failed = 0

        for idx, image_path in enumerate(images, start=1):
            entry: Dict[str, Any] = {
                'image': image_path,
                'hash': '',
                'status': 'failed',
                'supplier': '',
                'bill_date': '',
                'total_amount': 0.0,
                'result_file': None,
                'error': None,
            }
            try:
                file_hash = Path(image_path).stem
                entry['hash'] = file_hash

                # 1) OCR（写 data/output/{hash}.xlsx + .meta.json）
                excel_path = self.ocr_service.process_image(image_path)
                if not excel_path:
                    entry['error'] = 'OCR 失败'
                    failed += 1
                    results.append(entry)
                    if progress_cb:
                        progress_cb(idx, total, entry)
                    continue

                # 2) process_excel（识别元信息 + 重命名 + 落库）
                result_file = self.order_service.process_excel(excel_path)
                if not result_file:
                    entry['error'] = '处理失败'
                    failed += 1
                    results.append(entry)
                    if progress_cb:
                        progress_cb(idx, total, entry)
                    continue

                # 3) 回查元信息（process_excel 内部已落库）
                meta_row = self.order_service.metadata_db.get(file_hash) or {}
                entry['result_file'] = result_file
                entry['supplier'] = meta_row.get('supplier', '') or ''
                entry['bill_date'] = meta_row.get('bill_date', '') or ''
                entry['total_amount'] = float(meta_row.get('total_amount') or 0.0)
                entry['status'] = 'success'
                success += 1
                logger.info(
                    f"[{idx}/{total}] 处理完成: {Path(image_path).name} -> "
                    f"{Path(result_file).name} | 供应商={entry['supplier']!r} "
                    f"日期={entry['bill_date']!r} 金额={entry['total_amount']:.2f}"
                )
            except Exception as e:
                logger.error(f"[{idx}/{total}] 处理异常: {image_path}: {e}", exc_info=True)
                entry['error'] = str(e)
                failed += 1

            results.append(entry)
            if progress_cb:
                progress_cb(idx, total, entry)

        summary = {
            'total': total,
            'success': success,
            'failed': failed,
            'results': results,
        }
        logger.info(
            f"批量处理完成: 总 {total} 张, 成功 {success}, 失败 {failed}"
        )
        return summary