# ============================================================
# core/batch_import.py
# Import hàng loạt chứng từ từ file Excel
# ============================================================

import sys
import os
import re
import urllib.request
from typing import Optional, List, Dict

_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def _check_openpyxl():
    try:
        import openpyxl
        return openpyxl
    except ImportError:
        print("❌ Cần cài: pip install openpyxl")
        sys.exit(1)


# Cột bắt buộc trong Excel template
REQUIRED_COLS = ["NgayCT", "LoaiCT", "DienGiai", "TaiKhoanNo",
                 "TaiKhoanCo", "SoTien"]
OPTIONAL_COLS = ["SoCT", "DoiTuong", "MaDoiTac", "GhiChu"]


def create_import_template(output_path: str) -> str:
    """Tạo file Excel template để người dùng điền."""
    openpyxl = _check_openpyxl()
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "ChungTu"

    headers = REQUIRED_COLS + OPTIONAL_COLS + ["[Kết quả]"]
    for col, h in enumerate(headers, 1):
        cell = ws.cell(row=1, column=col, value=h)
        cell.font = openpyxl.styles.Font(bold=True)
        cell.fill = openpyxl.styles.PatternFill("solid", fgColor="1F4E79")
        cell.font = openpyxl.styles.Font(bold=True, color="FFFFFF")

    # Dữ liệu mẫu
    sample = [
        ["2026-02-01", "PT", "Thu tiền bán hàng KH ABC", "111", "131", 5000000, "PT001", "ABC Corp", "KH001", ""],
        ["2026-02-01", "PC", "Chi tiền mua văn phòng phẩm", "641", "111", 200000, "PC001", "", "", ""],
        ["2026-02-05", "HD", "Bán hàng cho KH XYZ", "131", "511", 10000000, "HD001", "XYZ Ltd", "KH002", ""],
        ["2026-02-05", "HD", "VAT 10% bán hàng KH XYZ", "131", "333", 1000000, "HD001", "", "", ""],
    ]
    for row_data in sample:
        ws.append(row_data)

    # Hướng dẫn (sheet 2)
    ws2 = wb.create_sheet("HuongDan")
    ws2["A1"] = "HƯỚNG DẪN NHẬP LIỆU"
    ws2["A3"] = "NgayCT: Ngày chứng từ, định dạng YYYY-MM-DD"
    ws2["A4"] = "LoaiCT: PT=Phiếu thu, PC=Phiếu chi, HD=Hóa đơn bán, HM=Hóa đơn mua, PB=Phân bổ, BT=Bút toán khác"
    ws2["A5"] = "TaiKhoanNo / TaiKhoanCo: Mã tài khoản kế toán (3-6 chữ số)"
    ws2["A6"] = "SoTien: Số tiền (không âm)"
    ws2["A7"] = "SoCT: Số chứng từ (bỏ trống = tự động)"
    ws2["A8"] = "MaDoiTac: Mã đối tác trong hệ thống (bỏ trống nếu không có)"

    wb.save(output_path)
    print(f"✅ Đã tạo template: {output_path}")
    return output_path


def download_gsheets_as_xlsx(url: str, output_path: str) -> bool:
    """Tải Google Sheets từ URL công khai và lưu thành file XLSX."""
    try:
        # Regex để trích xuất Sheet ID
        match = re.search(r"/spreadsheets/d/([a-zA-Z0-9-_]+)", url)
        if not match:
            raise ValueError("Link Google Sheets không hợp lệ. Vui lòng kiểm tra lại.")
        
        sheet_id = match.group(1)
        # Chuyển đổi sang link export XLSX
        export_url = f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=xlsx"
        
        # Download
        headers = {'User-Agent': 'Mozilla/5.0'}
        req = urllib.request.Request(export_url, headers=headers)
        with urllib.request.urlopen(req) as response, open(output_path, 'wb') as out_file:
            out_file.write(response.read())
        return True
    except Exception as e:
        print(f"❌ Lỗi tải Google Sheets: {e}")
        return False


def clear_local_vouchers(db_path: str):
    """Xoá toàn bộ chứng từ và bút toán trong database (để thay thế)."""
    from core.db_init import get_conn
    conn = get_conn(db_path)
    c = conn.cursor()
    try:
        c.execute("DELETE FROM journal_items")
        c.execute("DELETE FROM journal")
        conn.commit()
    finally:
        conn.close()

def get_all_vouchers_for_export(db_path: str) -> List[Dict]:
    """Lấy toàn bộ chứng từ để xuất ra Excel/Google Sheet."""
    from core.db_init import get_conn
    conn = get_conn(db_path)
    conn.row_factory = lambda cursor, row: dict(zip([col[0] for col in cursor.description], row))
    c = conn.cursor()
    
    # Lấy lộn ngược join để ra định dạng phẳng (flat) giống Excel template
    sql = """
        SELECT 
            j.voucher_date as NgayCT,
            j.voucher_type as LoaiCT,
            j.voucher_no as SoCT,
            ji.description as DienGiai,
            ji.account_code,
            ji.debit,
            ji.credit,
            ji.partner_code as MaDoiTac,
            j.notes as GhiChu
        FROM journal j
        JOIN journal_items ji ON j.id = ji.journal_id
        ORDER BY j.voucher_date ASC, j.id ASC
    """
    rows = c.execute(sql).fetchall()
    conn.close()
    
    # Chuyển đổi từ định dạng Nợ/Có sang định dạng TaiKhoanNo/TaiKhoanCo một dòng
    # Đây là logic gộp dòng phức tạp, tạm thời trả về flat để xử lý ở GUI hoặc đơn giản hóa
    return rows

def import_from_excel(db_path: str, excel_path: str,
                      dry_run: bool = False,
                      replace: bool = False,
                      sheet_name: Optional[str] = None,
                      user: str = "import") -> dict:
    """
    Import chứng từ từ file Excel.
    dry_run=True: chỉ validate, không ghi DB.
    replace=True: xoá dữ liệu cũ trước khi nạp.
    sheet_name: tên Sheet (Tab) cụ thể để nạp dữ liệu.
    """
    if not dry_run and replace:
        clear_local_vouchers(db_path)

    openpyxl = _check_openpyxl()
    from core.journal import post_voucher
    from core.db_init import get_conn

    wb = openpyxl.load_workbook(excel_path, data_only=True)
    
    # Ưu tiên sheet_name nếu có, nếu không thì tìm "ChungTu" hoặc lấy active
    if sheet_name and sheet_name in wb.sheetnames:
        ws = wb[sheet_name]
    elif "ChungTu" in wb.sheetnames:
        ws = wb["ChungTu"]
    else:
        ws = wb.active

    # Đọc header
    headers = [str(ws.cell(1, col).value or "").strip()
               for col in range(1, ws.max_column + 1)]

    def col_val(row, name):
        if name not in headers:
            return None
        idx = headers.index(name) + 1
        v = ws.cell(row, idx).value
        return v

    success = 0
    errors = []

    # Group dòng theo (SoCT, NgayCT, LoaiCT) để gộp thành 1 chứng từ
    from collections import defaultdict
    vouchers_map = defaultdict(list)

    for row in range(2, ws.max_row + 1):
        ngayct = col_val(row, "NgayCT")
        if not ngayct:
            continue
        ngayct_str = str(ngayct)[:10] if ngayct else None
        loai = str(col_val(row, "LoaiCT") or "BT").strip().upper()
        soct = str(col_val(row, "SoCT") or "").strip() or None
        key = (ngayct_str, loai, soct or f"_auto_{row}")

        tk_no  = str(col_val(row, "TaiKhoanNo")  or "").strip()
        tk_co  = str(col_val(row, "TaiKhoanCo")  or "").strip()
        sotien = float(col_val(row, "SoTien") or 0)
        dg     = str(col_val(row, "DienGiai") or "").strip()
        doitac = str(col_val(row, "MaDoiTac") or "").strip() or None

        if not tk_no or not tk_co or sotien <= 0:
            errors.append({"row": row, "error": f"Thiếu TK Nợ/Có hoặc số tiền ≤ 0"})
            continue

        vouchers_map[key].append({
            "row": row,
            "voucher_date": ngayct_str,
            "voucher_type": loai,
            "voucher_no": soct,
            "description": dg,
            "tk_no": tk_no,
            "tk_co": tk_co,
            "amount": sotien,
            "partner_code": doitac,
            "notes": str(col_val(row, "GhiChu") or ""),
        })

    # Tạo chứng từ
    conn = get_conn(db_path)
    for key, lines in vouchers_map.items():
        voucher_date, voucher_type, _ = key
        first = lines[0]
        entries = []
        for ln in lines:
            entries.append({"account_code": ln["tk_no"], "debit": ln["amount"], "credit": 0,
                            "description": ln["description"], "partner_code": ln.get("partner_code")})
            entries.append({"account_code": ln["tk_co"], "debit": 0, "credit": ln["amount"],
                            "description": ln["description"], "partner_code": ln.get("partner_code")})

        try:
            if not dry_run:
                vid = post_voucher(
                    db_path,
                    voucher_type=voucher_type,
                    voucher_date=voucher_date,
                    description=first["description"],
                    entries=entries,
                    voucher_no=first["voucher_no"],
                    notes=first["notes"],
                )
                # Ghi kết quả vào Excel
                for ln in lines:
                    result_col = headers.index("[Kết quả]") + 1 if "[Kết quả]" in headers else None
                    if result_col:
                        ws.cell(ln["row"], result_col, f"✅ #{vid}")
            success += 1
        except Exception as e:
            err_msg = str(e)
            errors.append({"rows": [ln["row"] for ln in lines], "error": err_msg})
            for ln in lines:
                result_col = headers.index("[Kết quả]") + 1 if "[Kết quả]" in headers else None
                if result_col:
                    ws.cell(ln["row"], result_col, f"❌ {err_msg[:40]}")

    conn.close()

    # Ghi lại file Excel với kết quả
    if not dry_run:
        result_path = excel_path.replace(".xlsx", "_result.xlsx")
        wb.save(result_path)
        print(f"✅ Đã ghi kết quả ra: {result_path}")

    mode = "[DRY RUN] " if dry_run else ""
    print(f"\n{mode}Kết quả import:")
    print(f"  ✅ Thành công : {success} chứng từ")
    print(f"  ❌ Lỗi       : {len(errors)} chứng từ")
    if errors:
        for e in errors[:10]:
            print(f"     Dòng {e.get('row', e.get('rows'))}: {e['error']}")

    return {"success": success, "errors": errors}
