import re
import json
import logging
from typing import List, Dict, Any

from app.core.settings import get_settings
from app.modules.agents.application.llm_client import LLMClient

logger = logging.getLogger("dscons.banking.reconciliation")

class ReconciliationEngine:
    def __init__(self, db_client):
        self.db = db_client
        self.settings = get_settings()
        self.llm_client = LLMClient(self.settings)
        
    async def suggest_matches(self, transactions: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Takes a list of raw transaction dicts and uses Gemini 3.1 Pro via Antigravity SDK
        to suggest matches (invoice numbers or partner names).
        """
        if not transactions:
            return transactions

        # Filter transactions that actually have a description
        tx_to_analyze = [tx for tx in transactions if tx.get("description")]
        if not tx_to_analyze:
            return transactions

        import asyncio
        semaphore = asyncio.Semaphore(3)

        async def process_chunk(chunk_start: int, chunk: List[Dict[str, Any]]):
            async with semaphore:
                prompt = "Bạn là AI Kế toán (AI Quỳnh) của hệ thống DSCons ERP. Hãy phân tích các giao dịch ngân hàng sau để tìm ra 'số hóa đơn' (nếu có) hoặc 'tên đối tác' (nếu có).\n"
                prompt += "Trả về duy nhất 1 mảng JSON chứa các object có định dạng: {\"index\": <int>, \"suggested_invoice_number\": \"<string|null>\", \"suggested_partner_name\": \"<string|null>\", \"confidence_score\": <float_0_to_1>, \"reason\": \"<string>\"}. Bạn BẮT BUỘC phải trả về đúng số lượng object bằng với số lượng giao dịch được cung cấp, giữ nguyên thứ tự.\n\n"
                prompt += "Danh sách giao dịch:\n"
                
                for idx, tx in enumerate(chunk):
                    prompt += f"[{idx}] Diễn giải: {tx.get('description')} | Tiền vào: {tx.get('credit_amount_vnd', 0)} | Tiền ra: {tx.get('debit_amount_vnd', 0)}\n"
        
                try:
                    response = await self.llm_client.create_chat_completion(
                        messages=[{"role": "user", "content": prompt}],
                        temperature=0.1,
                        agent_code="quynh"
                    )
                    
                    content = response.get("choices", [{}])[0].get("message", {}).get("content", "[]")
                    content = content.strip()
                    if content.startswith("```json"): content = content[7:]
                    if content.startswith("```"): content = content[3:]
                    if content.endswith("```"): content = content[:-3]
                    
                    ai_results = json.loads(content.strip())
                    
                    for idx, res in enumerate(ai_results):
                        if idx < len(chunk):
                            tx = chunk[idx]
                            tx["suggested_invoice_number"] = res.get("suggested_invoice_number")
                            tx["suggested_partner_name"] = res.get("suggested_partner_name")
                            tx["confidence_score"] = float(res.get("confidence_score", 0.0))
                            tx["reason"] = res.get("reason", "AI không tìm thấy thông tin.")
                            
                except Exception as e:
                    logger.error(f"[ReconciliationEngine] AI chunk failed: {e}")
                    # Fallback rule-based
                    for tx in chunk:
                        description = tx.get("description", "").upper()
                        invoice_match = re.search(r'HD\s*(\d{4,8})', description)
                        if invoice_match:
                            tx["suggested_invoice_number"] = invoice_match.group(1)
                            tx["confidence_score"] = 0.8
                            tx["reason"] = f"Detected invoice number {invoice_match.group(1)} in description"
                        elif "CONG TY A" in description:
                            tx["suggested_partner_name"] = "Cong Ty A"
                            tx["confidence_score"] = 0.5
                            tx["reason"] = "Description matches Partner A"
                        else:
                            tx["confidence_score"] = 0.0

        chunk_size = 20
        tasks = []
        for i in range(0, len(tx_to_analyze), chunk_size):
            chunk = tx_to_analyze[i:i + chunk_size]
            tasks.append(process_chunk(i, chunk))
            
        if tasks:
            await asyncio.gather(*tasks)
                    
        return transactions
