# ============================================================
# core/reports/financial_statements.py
# Báo cáo tài chính: Bảng CĐKT + KQHĐKD
# CLI: python core/cli.py company CTY001 bctc --year 2026
# ============================================================

import sqlite3
import os
from datetime import datetime
from typing import Optional

try:
    import openpyxl
    from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
    from openpyxl.utils import get_column_letter
    HAS_OPENPYXL = True
except ImportError:
    HAS_OPENPYXL = False


# ─── Helpers ─────────────────────────────────────────────────

def _sum_accounts(conn, account_prefixes: list, year: int, month_end: int = 12,
                  side: str = "debit") -> float:
    """Tổng số dư các TK theo prefix (debit hoặc credit)."""
    c = conn.cursor()
    total = 0.0
    for prefix in account_prefixes:
        rows = c.execute("""
            SELECT COALESCE(SUM(je.debit - je.credit), 0)
            FROM journal_entries je
            JOIN vouchers v ON v.id = je.voucher_id
            JOIN accounts a ON a.code = je.account_code
            WHERE a.code LIKE ?
              AND v.status = 'posted'
              AND v.period_year <= ?
              AND (v.period_year < ? OR v.period_month <= ?)
        """, (prefix + "%", year, year, month_end)).fetchone()
        val = rows[0] if rows else 0
        if side == "credit":
            val = -val
        total += max(0, val)
    return total


def _net(conn, debit_prefixes, credit_prefixes, year, month_end=12) -> float:
    """Số dư thuần = Nợ các TK - Có các TK."""
    c = conn.cursor()
    def sumup(prefixes, sign=1):
        t = 0
        for p in prefixes:
            r = c.execute("""
                SELECT COALESCE(SUM(je.debit - je.credit), 0)
                FROM journal_entries je
                JOIN vouchers v ON v.id = je.voucher_id
                WHERE je.account_code LIKE ?
                  AND v.status = 'posted'
                  AND v.period_year <= ?
                  AND (v.period_year < ? OR v.period_month <= ?)
            """, (p + "%", year, year, month_end)).fetchone()
            t += (r[0] if r else 0) * sign
        return t
    return sumup(debit_prefixes) - sumup(credit_prefixes)


# ─── Bảng Cân Đối Kế Toán ────────────────────────────────────

def calc_balance_sheet(conn: sqlite3.Connection, year: int, month_end: int = 12) -> dict:
    """
    Tính Bảng CĐKT theo TT200/2014.
    TK tài sản: dư Nợ. TK nguồn vốn: dư Có.
    """
    def nb(debits, credits=None):  # Net Balance
        return _net(conn, debits, credits or [], year, month_end)

    # ── TÀI SẢN NGẮN HẠN ──────────────────────────────────
    tien_tuong_duong = nb(["111", "112", "113"])
    dau_tu_ngan_han  = nb(["121"])
    phai_thu_kh      = nb(["131"])
    phai_thu_khac    = nb(["1388", "334", "141"])
    hang_ton_kho     = nb(["152", "153", "154", "155", "156", "157"])
    tai_san_ngan_han_khac = nb(["133", "151"])

    tsnh = (tien_tuong_duong + dau_tu_ngan_han + phai_thu_kh
            + phai_thu_khac + hang_ton_kho + tai_san_ngan_han_khac)

    # ── TÀI SẢN DÀI HẠN ──────────────────────────────────
    tscd_nguyen_gia  = nb(["211", "213"])
    tscd_khau_hao    = _net(conn, ["214"], [], year, month_end)  # dư Có → âm
    tscd_net         = tscd_nguyen_gia + tscd_khau_hao
    dau_tu_dai_han   = nb(["221", "222", "228"])
    tsdh_khac        = nb(["244"])

    tsdh = tscd_net + dau_tu_dai_han + tsdh_khac
    tong_ts = tsnh + tsdh

    # ── NỢ PHẢI TRẢ ───────────────────────────────────────
    vay_ngan_han     = _net(conn, [], ["311", "341"], year, month_end)
    phai_tra_ncc     = _net(conn, [], ["331"], year, month_end)
    thue_phai_nop    = _net(conn, [], ["333"], year, month_end)
    phai_tra_nld     = _net(conn, [], ["334"], year, month_end)
    chi_phi_phai_tra = _net(conn, [], ["335"], year, month_end)
    no_khac          = _net(conn, [], ["338"], year, month_end)

    no_ngan_han      = vay_ngan_han + phai_tra_ncc + thue_phai_nop + phai_tra_nld + chi_phi_phai_tra + no_khac
    no_dai_han       = _net(conn, [], ["341", "342"], year, month_end)
    tong_no          = no_ngan_han + no_dai_han

    # ── VỐN CHỦ SỞ HỮU ────────────────────────────────────
    von_gop          = _net(conn, [], ["411"], year, month_end)
    loi_nhuan_giu_lai = _net(conn, [], ["421"], year, month_end)
    vcsh             = von_gop + loi_nhuan_giu_lai
    tong_nguon_von   = tong_no + vcsh

    return {
        "year": year, "month_end": month_end,
        "asset": {
            "tsnh": tsnh,
            "tien": tien_tuong_duong,
            "dau_tu_ngan_han": dau_tu_ngan_han,
            "phai_thu_kh": phai_thu_kh,
            "hang_ton_kho": hang_ton_kho,
            "tsdh": tsdh,
            "tscd_net": tscd_net,
            "dau_tu_dai_han": dau_tu_dai_han,
            "tong_ts": tong_ts,
        },
        "liability": {
            "no_ngan_han": no_ngan_han,
            "vay_ngan_han": vay_ngan_han,
            "phai_tra_ncc": phai_tra_ncc,
            "thue_phai_nop": thue_phai_nop,
            "phai_tra_nld": phai_tra_nld,
            "no_dai_han": no_dai_han,
            "tong_no": tong_no,
        },
        "equity": {
            "von_gop": von_gop,
            "loi_nhuan_giu_lai": loi_nhuan_giu_lai,
            "vcsh": vcsh,
        },
        "tong_nguon_von": tong_nguon_von,
    }


# ─── Kết Quả Hoạt Động Kinh Doanh ────────────────────────────

def calc_income_statement(conn: sqlite3.Connection, year: int) -> dict:
    """Tính KQHĐKD năm theo TT200/2014."""
    c = conn.cursor()

    def ytd(prefixes, sign=1):
        t = 0
        for p in prefixes:
            r = c.execute("""
                SELECT COALESCE(SUM(je.credit - je.debit), 0)
                FROM journal_entries je
                JOIN vouchers v ON v.id = je.voucher_id
                WHERE je.account_code LIKE ?
                  AND v.status = 'posted'
                  AND v.period_year = ?
            """, (p + "%", year)).fetchone()
            t += (r[0] if r else 0) * sign
        return t

    doanh_thu     = ytd(["511", "515"])
    giam_tru      = ytd(["521"])
    dt_thuan      = doanh_thu - giam_tru

    gia_von       = ytd(["632"], sign=-1)  # dư Nợ → chi phí
    lngt          = dt_thuan - gia_von

    cp_ban_hang   = ytd(["641"], sign=-1)
    cp_qldn       = ytd(["642"], sign=-1)
    lntc          = ytd(["515"])
    cp_tc         = ytd(["635"], sign=-1)
    thu_khac      = ytd(["711"])
    cp_khac       = ytd(["811"], sign=-1)
    cp_thue_tndn  = ytd(["821"], sign=-1)

    lnhd = lngt - cp_ban_hang - cp_qldn + lntc - cp_tc
    lntruoc_thue  = lnhd + thu_khac - cp_khac
    lnsau_thue    = lntruoc_thue - cp_thue_tndn

    return {
        "year": year,
        "doanh_thu": doanh_thu,
        "giam_tru": giam_tru,
        "dt_thuan": dt_thuan,
        "gia_von": gia_von,
        "lngt": lngt,
        "cp_ban_hang": cp_ban_hang,
        "cp_qldn": cp_qldn,
        "lntc": lntc,
        "cp_tc": cp_tc,
        "lnhd": lnhd,
        "thu_khac": thu_khac,
        "cp_khac": cp_khac,
        "lntruoc_thue": lntruoc_thue,
        "cp_thue_tndn": cp_thue_tndn,
        "lnsau_thue": lnsau_thue,
    }


# ─── Xuất Excel BCTC ─────────────────────────────────────────

def export_bctc_excel(bs: dict, is_data: dict, out_dir: str, company_name: str = "") -> str:
    if not HAS_OPENPYXL:
        raise ImportError("Cần cài openpyxl: pip install openpyxl")

    os.makedirs(out_dir, exist_ok=True)
    year = bs["year"]
    fname = f"BCTC_{year}_{company_name or 'company'}.xlsx".replace(" ", "_")
    fpath = os.path.join(out_dir, fname)

    wb = openpyxl.Workbook()

    # ── Sheet 1: Bảng CĐKT ──────────────────────────────
    ws1 = wb.active
    ws1.title = "Bảng CĐKT"

    navy = "1F3864"; blue = "2E75B6"
    h1f  = Font(name="Arial", bold=True, size=13, color="FFFFFF")
    h2f  = Font(name="Arial", bold=True, size=10, color="FFFFFF")
    bf   = Font(name="Arial", bold=True, size=10)
    nf   = Font(name="Arial", size=10)
    ca   = Alignment(horizontal="center", vertical="center")
    la   = Alignment(horizontal="left", vertical="center", indent=1)
    ra   = Alignment(horizontal="right", vertical="center")
    thin = Side(style="thin", color="BFBFBF")
    bd   = Border(left=thin, right=thin, top=thin, bottom=thin)
    def fill(c): return PatternFill("solid", fgColor=c)
    fmt  = '#,##0'

    ws1.column_dimensions["A"].width = 42
    ws1.column_dimensions["B"].width = 8
    ws1.column_dimensions["C"].width = 20
    ws1.column_dimensions["D"].width = 20

    # Title
    ws1.merge_cells("A1:D1")
    ws1["A1"] = f"BẢNG CÂN ĐỐI KẾ TOÁN — NĂM {year}"
    ws1["A1"].font = h1f; ws1["A1"].fill = fill(navy); ws1["A1"].alignment = ca
    ws1.row_dimensions[1].height = 28

    ws1.merge_cells("A2:D2")
    ws1["A2"] = f"Đơn vị: {company_name}  |  Ngày lập: {datetime.now().strftime('%d/%m/%Y')}"
    ws1["A2"].font = Font(name="Arial", size=10); ws1["A2"].alignment = ca
    ws1.row_dimensions[2].height = 18

    # Header row
    for col, (hdr, w) in enumerate(zip(["Chỉ tiêu", "Mã số", "Cuối năm", "Đầu năm"], [42,8,20,20]), 1):
        c = ws1.cell(row=4, column=col, value=hdr)
        c.font = h2f; c.fill = fill(blue); c.alignment = ca; c.border = bd
    ws1.row_dimensions[4].height = 20

    def write_row(ws, row, label, code, val, indent=0, bold=False, fill_color=None):
        cells = [
            (1, label, Alignment(horizontal="left", vertical="center", indent=indent)),
            (2, code, ca),
            (3, val if val != 0 else None, ra),
            (4, None, ra),
        ]
        for col, v, align in cells:
            cell = ws.cell(row=row, column=col, value=v)
            cell.font = bf if bold else nf
            cell.alignment = align
            cell.border = bd
            if fill_color:
                cell.fill = fill(fill_color)
            if col == 3 and v is not None:
                cell.number_format = fmt
        return row + 1

    a = bs["asset"]; l = bs["liability"]; e = bs["equity"]
    row = 5

    # Tài sản
    row = write_row(ws1, row, "A. TÀI SẢN NGẮN HẠN", "100", a["tsnh"], bold=True, fill_color="E2EFDA")
    row = write_row(ws1, row, "I. Tiền và tương đương tiền", "110", a["tien"], indent=1)
    row = write_row(ws1, row, "II. Đầu tư tài chính ngắn hạn", "120", a["dau_tu_ngan_han"], indent=1)
    row = write_row(ws1, row, "III. Các khoản phải thu ngắn hạn", "130", a["phai_thu_kh"], indent=1)
    row = write_row(ws1, row, "IV. Hàng tồn kho", "140", a["hang_ton_kho"], indent=1)
    row = write_row(ws1, row, "B. TÀI SẢN DÀI HẠN", "200", a["tsdh"], bold=True, fill_color="E2EFDA")
    row = write_row(ws1, row, "I. Tài sản cố định (thuần)", "210", a["tscd_net"], indent=1)
    row = write_row(ws1, row, "II. Đầu tư tài chính dài hạn", "220", a["dau_tu_dai_han"], indent=1)
    row = write_row(ws1, row, "TỔNG CỘNG TÀI SẢN (A+B)", "270", a["tong_ts"], bold=True, fill_color="C6EFCE")
    row += 1

    # Nguồn vốn
    row = write_row(ws1, row, "C. NỢ PHẢI TRẢ", "300", l["tong_no"], bold=True, fill_color="FCE4D6")
    row = write_row(ws1, row, "I. Nợ ngắn hạn", "310", l["no_ngan_han"], indent=1)
    row = write_row(ws1, row, "  - Vay ngắn hạn", "311", l["vay_ngan_han"], indent=2)
    row = write_row(ws1, row, "  - Phải trả nhà cung cấp", "312", l["phai_tra_ncc"], indent=2)
    row = write_row(ws1, row, "  - Thuế và các khoản phải nộp", "313", l["thue_phai_nop"], indent=2)
    row = write_row(ws1, row, "  - Phải trả NLĐ", "314", l["phai_tra_nld"], indent=2)
    row = write_row(ws1, row, "II. Nợ dài hạn", "330", l["no_dai_han"], indent=1)
    row = write_row(ws1, row, "D. VỐN CHỦ SỞ HỮU", "400", e["vcsh"], bold=True, fill_color="FCE4D6")
    row = write_row(ws1, row, "  - Vốn đầu tư của CSH", "410", e["von_gop"], indent=2)
    row = write_row(ws1, row, "  - Lợi nhuận sau thuế chưa phân phối", "420", e["loi_nhuan_giu_lai"], indent=2)
    row = write_row(ws1, row, "TỔNG CỘNG NGUỒN VỐN (C+D)", "440", bs["tong_nguon_von"], bold=True, fill_color="FFFF99")
    ws1.freeze_panes = "A5"

    # ── Sheet 2: KQHĐKD ──────────────────────────────────
    ws2 = wb.create_sheet("KQHĐKD")
    ws2.column_dimensions["A"].width = 45
    ws2.column_dimensions["B"].width = 8
    ws2.column_dimensions["C"].width = 22

    ws2.merge_cells("A1:C1")
    ws2["A1"] = f"KẾT QUẢ HOẠT ĐỘNG KINH DOANH — NĂM {year}"
    ws2["A1"].font = h1f; ws2["A1"].fill = fill(navy); ws2["A1"].alignment = ca
    ws2.row_dimensions[1].height = 28

    ws2.merge_cells("A2:C2")
    ws2["A2"] = f"Đơn vị: {company_name}   (Đơn vị tính: VND)"
    ws2["A2"].font = Font(name="Arial", size=10); ws2["A2"].alignment = ca

    for col, hdr in enumerate(["Chỉ tiêu", "Mã số", "Năm nay"], 1):
        c = ws2.cell(row=4, column=col, value=hdr)
        c.font = h2f; c.fill = fill(blue); c.alignment = ca; c.border = bd
    ws2.row_dimensions[4].height = 20

    def wr2(row, label, code, val, bold=False, fc=None):
        for col, (v, al) in enumerate([(label, la), (code, ca), (val if val != 0 else None, ra)], 1):
            cell = ws2.cell(row=row, column=col, value=v)
            cell.font = bf if bold else nf
            cell.alignment = al; cell.border = bd
            if fc: cell.fill = fill(fc)
            if col == 3 and v is not None:
                cell.number_format = fmt
        return row + 1

    is_ = is_data
    row = 5
    row = wr2(row, "1. Doanh thu bán hàng và cung cấp DV", "01", is_["doanh_thu"])
    row = wr2(row, "2. Các khoản giảm trừ doanh thu", "02", is_["giam_tru"])
    row = wr2(row, "3. Doanh thu thuần", "10", is_["dt_thuan"], bold=True, fc="E2EFDA")
    row = wr2(row, "4. Giá vốn hàng bán", "11", is_["gia_von"])
    row = wr2(row, "5. Lợi nhuận gộp (3-4)", "20", is_["lngt"], bold=True, fc="E2EFDA")
    row = wr2(row, "6. Doanh thu hoạt động tài chính", "21", is_["lntc"])
    row = wr2(row, "7. Chi phí tài chính", "22", is_["cp_tc"])
    row = wr2(row, "8. Chi phí bán hàng", "25", is_["cp_ban_hang"])
    row = wr2(row, "9. Chi phí QLDN", "26", is_["cp_qldn"])
    row = wr2(row, "10. Lợi nhuận từ HĐKD", "30", is_["lnhd"], bold=True, fc="E2EFDA")
    row = wr2(row, "11. Thu nhập khác", "31", is_["thu_khac"])
    row = wr2(row, "12. Chi phí khác", "32", is_["cp_khac"])
    row = wr2(row, "13. LN trước thuế (30+31-32)", "50", is_["lntruoc_thue"], bold=True, fc="C6EFCE")
    row = wr2(row, "14. Chi phí thuế TNDN", "51", is_["cp_thue_tndn"])
    row = wr2(row, "15. LN sau thuế TNDN", "60", is_["lnsau_thue"], bold=True, fc="FFFF99")
    ws2.freeze_panes = "A5"

    wb.save(fpath)
    return fpath


# ─── In console ──────────────────────────────────────────────

def print_bctc(bs: dict, is_data: dict) -> None:
    fmt = lambda x: f"{x:>18,.0f}"
    print(f"\n{'='*55}")
    print(f"  BẢNG CÂN ĐỐI KẾ TOÁN — NĂM {bs['year']}")
    print(f"{'='*55}")
    a = bs["asset"]
    print(f"  A. TÀI SẢN NGẮN HẠN       {fmt(a['tsnh'])}")
    print(f"     Tiền & TĐT             {fmt(a['tien'])}")
    print(f"     Phải thu KH            {fmt(a['phai_thu_kh'])}")
    print(f"     Hàng tồn kho           {fmt(a['hang_ton_kho'])}")
    print(f"  B. TÀI SẢN DÀI HẠN        {fmt(a['tsdh'])}")
    print(f"  ─── TỔNG TÀI SẢN           {fmt(a['tong_ts'])}")
    l = bs["liability"]
    print(f"  C. NỢ PHẢI TRẢ             {fmt(l['tong_no'])}")
    e = bs["equity"]
    print(f"  D. VỐN CHỦ SỞ HỮU         {fmt(e['vcsh'])}")
    print(f"  ─── TỔNG NGUỒN VỐN         {fmt(bs['tong_nguon_von'])}")

    is_ = is_data
    print(f"\n{'='*55}")
    print(f"  KẾT QUẢ HĐKD — NĂM {is_['year']}")
    print(f"{'='*55}")
    print(f"  Doanh thu thuần            {fmt(is_['dt_thuan'])}")
    print(f"  Giá vốn hàng bán           {fmt(is_['gia_von'])}")
    print(f"  Lợi nhuận gộp              {fmt(is_['lngt'])}")
    print(f"  Chi phí BH+QLDN            {fmt(is_['cp_ban_hang'] + is_['cp_qldn'])}")
    sign = "✅" if is_['lnsau_thue'] >= 0 else "🔴"
    print(f"  {sign} LN SAU THUẾ            {fmt(is_['lnsau_thue'])}")
    print(f"{'='*55}\n")


# ─── Entry point ─────────────────────────────────────────────

def run_bctc(db_path: str, year: int, out_dir: Optional[str] = None,
             company_name: str = "") -> dict:
    conn = sqlite3.connect(db_path)
    bs   = calc_balance_sheet(conn, year)
    is_  = calc_income_statement(conn, year)
    print_bctc(bs, is_)
    if out_dir:
        fpath = export_bctc_excel(bs, is_, out_dir, company_name)
        print(f"📄 Đã xuất BCTC: {fpath}")
    conn.close()
    return {"balance_sheet": bs, "income_statement": is_}
