import os
import json
import sqlite3
from datetime import datetime
from docx import Document
from typing import Dict, Any, Optional, List

class TaxReportGenerator:
    """
    Hỗ trợ xuất báo cáo thuế HKD (01/CNKD) ra file Word (.docx)
    """
    
    def __init__(self, template_path: str, db_path: str, info_path: str):
        self.template_path = template_path
        self.db_path = db_path
        self.info_path = info_path
        
    def _get_company_info(self) -> Dict[str, str]:
        """Lấy thông tin hộ kinh doanh từ settings.json."""
        if os.path.exists(self.info_path):
            with open(self.info_path, 'r', encoding='utf-8') as f:
                return json.load(f).get("company", {})
        return {}

    def _get_revenue_data(self, year: int, month: Optional[int] = None, quarter: Optional[int] = None) -> Dict[str, float]:
        """ Tóm tắt doanh thu từ revenue.db theo nhóm ngành thuế. """
        conn = sqlite3.connect(self.db_path)
        conn.row_factory = sqlite3.Row
        
        query = "SELECT category, SUM(amount) as total FROM daily_revenue WHERE "
        params = []
        
        if month:
            query += "entry_date LIKE ?"
            params.append(f"{year}-{month:02d}%")
        elif quarter:
            months = range((quarter-1)*3 + 1, quarter*3 + 1)
            query += "(" + " OR ".join(["entry_date LIKE ?" for _ in months]) + ")"
            for m in months:
                params.append(f"{year}-{m:02d}%")
        else:
            query += "entry_date LIKE ?"
            params.append(f"{year}%")
            
        query += " AND (category LIKE 'thu_%' OR category = 'ban_hang' OR category = 'dich_vu') GROUP BY category"
        
        rows = conn.execute(query, params).fetchall()
        conn.close()
        
        # Mặc định gom hết vào Nhóm Phân phối (1%) nếu chưa có phân loại chi tiết
        result = {
            "28a": 0.0, # Phân phối (1%)
            "29a": 0.0, # Dịch vụ (5%)
            "30a": 0.0, # Sản xuất/Vận tải (3%)
            "31a": 0.0  # Khác (2%)
        }
        
        for row in rows:
            cat = row["category"]
            val = row["total"]
            if cat in ("thu_ban_hang", "thu_ban_hang_ck", "ban_hang"):
                result["28a"] += val
            elif "dich_vu" in cat:
                result["29a"] += val
            else:
                # Tạm thời gom vào 31a cho các loại thu khác
                result["31a"] += val
                
        return result

    def _get_inventory_data(self, year: int, month: Optional[int] = None, quarter: Optional[int] = None) -> List[Dict[str, Any]]:
        """ Trích xuất tóm tắt Nhập-Xuất-Tồn từ daily_revenue cho Phụ lục 01-2. """
        conn = sqlite3.connect(self.db_path)
        conn.row_factory = sqlite3.Row
        
        # 1. Xác định khoảng thời gian
        if month:
            start_date = f"{year}-{month:02d}-01"
            next_month = month + 1 if month < 12 else 1
            next_year = year if month < 12 else year + 1
            end_date = f"{next_year}-{next_month:02d}-01"
        elif quarter:
            start_date = f"{year}-{(quarter-1)*3 + 1:02d}-01"
            end_month = quarter * 3 + 1
            if end_month > 12:
                end_date = f"{year + 1}-01-01"
            else:
                end_date = f"{year}-{end_month:02d}-01"
        else:
            start_date = f"{year}-01-01"
            end_date = f"{year + 1}-01-01"

        # 2. Lấy danh sách sản phẩm có phát sinh
        sql_products = "SELECT DISTINCT product_code FROM daily_revenue WHERE product_code IS NOT NULL AND product_code != ''"
        products = [r["product_code"] for r in conn.execute(sql_products).fetchall()]
        
        result = []
        for code in products:
            # Tên và đơn vị (lấy từ bản ghi mới nhất có code này)
            meta = conn.execute("SELECT note, product_code FROM daily_revenue WHERE product_code = ? ORDER BY entry_date DESC LIMIT 1", (code,)).fetchone()
            name = meta["note"] if meta and meta["note"] else code
            unit = "Cái" # Mặc định
            
            # Số dư đầu kỳ (Opening)
            sql_open = """
                SELECT 
                    SUM(CASE WHEN category = 'chi_nhap_hang' THEN quantity ELSE 0 END) -
                    SUM(CASE WHEN category IN ('thu_ban_hang', 'thu_ban_hang_ck', 'ban_hang') THEN quantity ELSE 0 END) as qty,
                    SUM(CASE WHEN category = 'chi_nhap_hang' THEN amount ELSE 0 END) -
                    SUM(CASE WHEN category IN ('thu_ban_hang', 'thu_ban_hang_ck', 'ban_hang') THEN amount ELSE 0 END) as val
                FROM daily_revenue WHERE product_code = ? AND entry_date < ?
            """
            row_open = conn.execute(sql_open, (code, start_date)).fetchone()
            q_open = row_open["qty"] or 0.0
            v_open = row_open["val"] or 0.0
            
            # Nhập/Xuất trong kỳ
            sql_period = """
                SELECT 
                    SUM(CASE WHEN category = 'chi_nhap_hang' THEN quantity ELSE 0 END) as q_in,
                    SUM(CASE WHEN category = 'chi_nhap_hang' THEN amount ELSE 0 END) as v_in,
                    SUM(CASE WHEN category IN ('thu_ban_hang', 'thu_ban_hang_ck', 'ban_hang') THEN quantity ELSE 0 END) as q_out,
                    SUM(CASE WHEN category IN ('thu_ban_hang', 'thu_ban_hang_ck', 'ban_hang') THEN amount ELSE 0 END) as v_out
                FROM daily_revenue WHERE product_code = ? AND entry_date >= ? AND entry_date < ?
            """
            row_period = conn.execute(sql_period, (code, start_date, end_date)).fetchone()
            q_in = row_period["q_in"] or 0.0
            v_in = row_period["v_in"] or 0.0
            q_out = row_period["q_out"] or 0.0
            v_out = row_period["v_out"] or 0.0
            
            # Tồn cuối kỳ
            q_end = q_open + q_in - q_out
            v_end = v_open + v_in - v_out
            
            if q_open != 0 or q_in != 0 or q_out != 0:
                result.append({
                    "name": name, "unit": unit,
                    "q_open": q_open, "v_open": v_open,
                    "q_in": q_in, "v_in": v_in,
                    "q_out": q_out, "v_out": v_out,
                    "q_end": q_end, "v_end": v_end
                })
        
        conn.close()
        return result

    def _get_expense_data(self, year: int, month: Optional[int] = None, quarter: Optional[int] = None) -> Dict[str, float]:
        """ Phân loại chi phí quản lý cho Phụ lục 01-2. """
        conn = sqlite3.connect(self.db_path)
        conn.row_factory = sqlite3.Row
        
        # Query cơ bản
        query = "SELECT note, amount FROM daily_revenue WHERE category = 'chi_hoat_dong' AND "
        params = []
        if month:
            query += "entry_date LIKE ?"
            params.append(f"{year}-{month:02d}%")
        elif quarter:
            months = range((quarter-1)*3 + 1, quarter*3 + 1)
            query += "(" + " OR ".join(["entry_date LIKE ?" for _ in months]) + ")"
            for m in months:
                params.append(f"{year}-{m:02d}%")
        else:
            query += "entry_date LIKE ?"
            params.append(f"{year}%")
            
        rows = conn.execute(query, params).fetchall()
        conn.close()
        
        expenses = {
            "24": 0.0, # Nhân công
            "25": 0.0, # Điện
            "26": 0.0, # Nước
            "27": 0.0, # Viễn thông
            "28": 0.0, # Thuê kho
            "29": 0.0, # Quản lý
            "30": 0.0  # Khác
        }
        
        # Keyword mapping đơn giản từ note
        mapping = {
            "lương": "24", "nhân viên": "24",
            "điện": "25", "tiền điện": "25",
            "nước": "26", "tiền nước": "26",
            "mạng": "27", "internet": "27", "điện thoại": "27", "viễn thông": "27",
            "thuê": "28", "mặt bằng": "28", "kho": "28"
        }
        
        for row in rows:
            note = row["note"].lower()
            amount = row["amount"]
            found = False
            for kw, code in mapping.items():
                if kw in note:
                    expenses[code] += amount
                    found = True
                    break
            if not found:
                expenses["30"] += amount
                
        return expenses

    def generate(self, year: int, month: Optional[int] = None, quarter: Optional[int] = None, output_path: str = None) -> str:
        """Thực thi tạo báo cáo (Tờ khai + Phụ lục nếu có)."""
        if not os.path.exists(self.template_path):
            raise FileNotFoundError(f"Không tìm thấy mẫu tại: {self.template_path}")
            
        doc = Document(self.template_path)
        info = self._get_company_info()
        revenue = self._get_revenue_data(year, month, quarter)
        
        # 1. Điền thông tin chung
        placeholders = {
            "[04] Người nộp thuế:": f"[04] Tên người nộp thuế: {info.get('legal_name', info.get('name', ''))}",
            "[07] Mã số thuế:": f"[07] Mã số thuế: {info.get('tax_id', '')}",
            "[05] Mã số thuế:": f"[05] Mã số thuế: {info.get('tax_id', '')}", # Cho phụ lục
            "[12b12c12d12đ] Địa chỉ:": f"[12b,c,d,đ] Địa chỉ: {info.get('address', '')}",
            "[14] Điện thoại:": f"[14] Điện thoại: {info.get('phone', '')}",
            "[16] Email:": f"[16] Email: {info.get('email', '')}",
        }
        
        for p in doc.paragraphs:
            text = p.text.strip()
            # Xử lý placeholder thông thường
            for key, val in placeholders.items():
                if key in text:
                    p.text = val
            
            # Đánh dấu phương pháp kê khai
            if "HKD, CNKD nộp thuế theo phương pháp kê khai" in text:
                p.text = "☒ HKD, CNKD nộp thuế theo phương pháp kê khai"
            
            # Xử lý kỳ tính thuế cho Phụ lục Table (Table 1 trong Appendix)
            # Thường nằm trong paragraph nếu không phải bảng, nhưng ở đây Appendix dùng bảng
        
        # 2. Điền các Bảng
        for table in doc.tables:
            if not table.rows:
                continue
                
            # 2a. Bảng kỳ tính thuế (Thường là Table 1 trong Appendix)
            try:
                if len(table.rows) > 0 and len(table.rows[0].cells) > 0 and "[01] Kỳ tính thuế:" in table.rows[0].cells[0].text:
                    if month and len(table.rows[0].cells) > 1:
                        table.rows[0].cells[1].text = f"[01a] Tháng {month:02d} năm {year}"
                    elif quarter and len(table.rows) > 1 and len(table.rows[1].cells) > 1:
                        table.rows[1].cells[1].text = f"[01b] Quý {quarter} năm {year}"
            except Exception:
                pass

            # 2b. Bảng Doanh thu (Mẫu 01/CNKD)
            for row in table.rows:
                cells_text = [c.text.strip() for c in row.cells]
                row_content = "".join(cells_text)
                for code in ["28a", "29a", "30a", "31a"]:
                    if f"[{code}]" in row_content:
                        for i, cell in enumerate(row.cells):
                            if "……" in cell.text or not cell.text.strip():
                                if i >= 1: # Chấp nhận từ cột 2 trở đi
                                    cell.text = f"{revenue[code]:,.0f}"
                                    break
                                    
            # 2c. Bảng Nhập-Xuất-Tồn (Table 2 Appendix) - Mẫu 01-2/BK-HĐKD
            try:
                if len(table.rows) > 2 and len(table.rows[2].cells) > 0 and "[06]" in table.rows[2].cells[0].text:
                    inventory = self._get_inventory_data(year, month, quarter)
                    for i, item in enumerate(inventory):
                        if i + 3 < len(table.rows):
                            row = table.rows[i + 3]
                        else:
                            row = table.add_row()
                        
                        if len(row.cells) >= 10:
                            row.cells[0].text = item["name"]
                            row.cells[1].text = item["unit"]
                            row.cells[2].text = f"{item['q_open']:.2f}"
                            row.cells[3].text = f"{item['v_open']:,.0f}"
                            row.cells[4].text = f"{item['q_in']:.2f}"
                            row.cells[5].text = f"{item['v_in']:,.0f}"
                            row.cells[6].text = f"{item['q_out']:.2f}"
                            row.cells[7].text = f"{item['v_out']:,.0f}"
                            row.cells[8].text = f"{item['q_end']:.2f}"
                            row.cells[9].text = f"{item['v_end']:,.0f}"
            except Exception:
                pass

            # 2d. Bảng Chi phí (Table 3 Appendix) - Mẫu 01-2/BK-HĐKD
            try:
                if len(table.rows) > 1 and len(table.rows[1].cells) > 0 and "Chi phí nhân công" in table.rows[1].cells[0].text:
                    expenses = self._get_expense_data(year, month, quarter)
                    for row in table.rows:
                        if len(row.cells) > 2:
                            m_text = row.cells[1].text.strip() # Cột Mã chỉ tiêu
                            for code, val in expenses.items():
                                if f"[{code}]" in m_text:
                                    row.cells[2].text = f"{val:,.0f}"
            except Exception:
                pass

        if not output_path:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            prefix = "ToKhai" if "01-CNKD" in self.template_path else "PhuLuc"
            filename = f"{prefix}_{year}_{month or 'Q'+str(quarter)}_{timestamp}.docx"
            output_path = os.path.join(os.path.dirname(self.db_path), "..", "reports", filename)
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
        doc.save(output_path)
        return os.path.abspath(output_path)
