import io
from decimal import Decimal

import pytest
from fastapi.testclient import TestClient
from openpyxl import load_workbook

from app.main import create_app
from app.modules.auth.application.auth_service import AuthService
from app.modules.invoices.application.invoice_processing.misa_exporter import vietnamese_number_to_words
from app.modules.invoices.application.invoice_processing_service import InvoiceProcessingService


@pytest.fixture
def auth_headers():
    auth = AuthService()
    token = auth.create_jwt_token(
        {
            "id": "misa-test-accountant-01",
            "sub": "misa-test-accountant-01",
            "email": "accountant_misa@dinhsonconstruction.com",
            "full_name": "Kế Toán Xuất HĐ MISA",
            "role": "accountant",
            "company_id": "0202111150",
        }
    )
    return {"Authorization": f"Bearer {token}"}


class TestInvoiceMisaExport:
    def test_vietnamese_number_to_words_conversions(self):
        assert vietnamese_number_to_words(0) == "Không đồng chẵn."
        assert vietnamese_number_to_words(105) == "Một trăm linh năm đồng chẵn."
        assert vietnamese_number_to_words(115) == "Một trăm mười lăm đồng chẵn."
        assert vietnamese_number_to_words(125) == "Một trăm hai mươi lăm đồng chẵn."
        assert (
            vietnamese_number_to_words(15400000)
            == "Mười lăm triệu bốn trăm nghìn đồng chẵn."
        )
        assert (
            vietnamese_number_to_words(1250000000)
            == "Một tỷ hai trăm năm mươi triệu đồng chẵn."
        )
        assert "tỷ" in vietnamese_number_to_words(Decimal(5432100000))

    def test_generate_misa_xml_structure(self):
        service = InvoiceProcessingService()
        inv_dict = {
            "invoice_number": "00000088",
            "invoice_series": "1C26TDS",
            "template_code": "1",
            "issue_date": "2026-08-29",
            "seller_name": "CÔNG TY TNHH XÂY DỰNG ĐỊNH SƠN",
            "seller_tax_code": "0202111150",
            "seller_address": "Hải Phòng",
            "buyer_name": "BAN QUẢN LÝ DỰ ÁN ĐẦU TƯ XÂY DỰNG KIẾN THỤY",
            "buyer_tax_code": "0200888999",
            "buyer_address": "Kiến Thụy, Hải Phòng",
            "subtotal_amount_vnd": Decimal(100000000),
            "vat_rate_percent": Decimal(8),
            "vat_amount_vnd": Decimal(8000000),
            "total_amount_vnd": Decimal(108000000),
        }
        items = [
            {
                "item_name": "Bê tông thương phẩm M300 R28",
                "item_code": "BT-300",
                "unit": "m3",
                "quantity": 100.0,
                "unit_price_vnd": 1000000,
                "amount_before_vat_vnd": 100000000,
                "vat_amount_vnd": 8000000,
                "total_item_amount_vnd": 108000000,
            }
        ]

        xml_output = service.generate_misa_xml(inv_dict, items)
        assert "<?xml version=" in xml_output
        assert "<InvoiceNo>00000088</InvoiceNo>" in xml_output
        assert "<InvoiceSeries>1C26TDS</InvoiceSeries>" in xml_output
        assert "<SellerTaxCode>0202111150</SellerTaxCode>" in xml_output
        assert "<BuyerTaxCode>0200888999</BuyerTaxCode>" in xml_output
        assert "<TotalAmountWithVAT>108000000.0000</TotalAmountWithVAT>" in xml_output
        assert "Bê tông thương phẩm M300" in xml_output
        assert "MISA meInvoice" in xml_output

    def test_issue_output_invoice_and_export_lifecycle(self, auth_headers):
        service = InvoiceProcessingService()
        created_invoice_id = None

        try:
            # 1. Issue a new output invoice
            res = service.issue_output_invoice(
                buyer_name="UBND XÃ KIẾN MINH",
                buyer_tax_code="0201234567",
                buyer_address="Xã Kiến Minh, Kiến Thụy, Hải Phòng",
                items=[
                    {
                        "item_name": "Thi công xây lắp kênh Đồng Dầm đợt 1",
                        "item_code": "TC-KD-01",
                        "unit": "Đợt",
                        "quantity": 1.0,
                        "unit_price_vnd": 50000000,
                    },
                    {
                        "item_name": "Cát san lấp đầm chặt K95",
                        "item_code": "VL-CAT",
                        "unit": "m3",
                        "quantity": 50.0,
                        "unit_price_vnd": 200000,
                    },
                ],
                vat_rate_percent=8.0,
                invoice_series="1C26TDS",
                invoice_number="99990001",
                notes="Nghiệm thu thanh toán giai đoạn 1",
                user_name="Kế Toán Kiểm Thử MISA",
            )

            assert res["status"] == "success"
            created_invoice_id = res["invoice_id"]
            assert res["invoice_number"] == "99990001"
            assert res["total_amount_vnd"] == 64800000.0
            assert ("Sáu mươi bốn triệu" in res["amount_in_words"]) or (
                "Sáu mươi tư triệu" in res["amount_in_words"]
            )
            assert "tám trăm nghìn đồng chẵn." in res["amount_in_words"]

            # 2. Render HTML view
            html = service.render_misa_invoice_html(created_invoice_id)
            assert "HÓA ĐƠN GIÁ TRỊ GIA TĂNG" in html
            assert "99990001" in html
            assert "UBND XÃ KIẾN MINH" in html
            assert "Thi công xây lắp kênh Đồng Dầm" in html
            assert "CÔNG TY TNHH XÂY DỰNG ĐỊNH SƠN" in html

            # 3. Export Excel MISA
            excel_bytes = service.export_misa_excel(direction="output")
            assert len(excel_bytes) > 1000
            wb = load_workbook(io.BytesIO(excel_bytes))
            ws = wb.active
            assert "BẢNG KÊ HÓA ĐƠN ĐIỆN TỬ" in ws["A1"].value
            assert "CÔNG TY TNHH XÂY DỰNG ĐỊNH SƠN" in ws["A2"].value

            # 4. Test API Endpoints
            app = create_app()
            client = TestClient(app)

            # 4.1 Export XML endpoint
            xml_resp = client.get(
                f"/v1/erp/invoices/{created_invoice_id}/export-xml",
                headers=auth_headers,
            )
            assert xml_resp.status_code == 200
            assert "attachment; filename=" in xml_resp.headers.get(
                "Content-Disposition", ""
            )
            assert "Hoa_Don_1C26TDS_99990001.xml" in xml_resp.headers.get(
                "Content-Disposition", ""
            )
            assert b"UBND" in xml_resp.content

            # 4.2 HTML view endpoint
            html_resp = client.get(
                f"/v1/erp/invoices/{created_invoice_id}/html-view", headers=auth_headers
            )
            assert html_resp.status_code == 200
            assert "text/html" in html_resp.headers.get("Content-Type", "")
            assert "DSCONS" in html_resp.text

            # 4.3 Export Excel endpoint
            xls_resp = client.get(
                "/v1/erp/invoices/export/misa-excel?direction=output",
                headers=auth_headers,
            )
            assert xls_resp.status_code == 200
            assert "spreadsheetml.sheet" in xls_resp.headers.get("Content-Type", "")

        finally:
            if created_invoice_id:
                with service.get_connection() as conn:
                    with conn.cursor() as cur:
                        cur.execute(
                            "DELETE FROM erp_invoice_audit_logs WHERE invoice_id = %s",
                            (created_invoice_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoice_items WHERE invoice_id = %s",
                            (created_invoice_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoices WHERE id = %s",
                            (created_invoice_id,),
                        )
                        conn.commit()

    def test_draft_invoice_and_signing_lifecycle(self, auth_headers):
        service = InvoiceProcessingService()
        draft_id = None

        try:
            # 1. Create a DRAFT invoice
            draft_res = service.issue_output_invoice(
                buyer_name="BAN QUẢN LÝ DỰ ÁN HUYỆN TIÊN LÃNG",
                buyer_tax_code="0203334445",
                items=[
                    {
                        "item_name": "San lấp mặt bằng dự án Cụm CN Tiên Lãng",
                        "unit": "m3",
                        "quantity": 1000.0,
                        "unit_price_vnd": 120000.0,
                        "vat_rate_percent": 8.0,
                    }
                ],
                invoice_series="1C26TDS",
                invoice_number="99990003",
                is_draft=True,
                user_name="Kế Toán Nháp",
            )

            assert draft_res["status"] == "success"
            draft_id = draft_res["invoice_id"]
            assert draft_res["is_draft"] is True

            # Verify in DB
            detail = service.get_invoice_detail(draft_id)
            assert detail["status"] == "draft"
            assert detail["signature_valid"] is False

            # 2. Sign and issue the draft invoice
            sign_res = service.sign_and_issue_invoice(
                draft_id, user_name="Kế Toán Trưởng"
            )
            assert sign_res["status"] == "success"

            # Verify status is now 'valid'
            detail_signed = service.get_invoice_detail(draft_id)
            assert detail_signed["status"] == "valid"
            assert detail_signed["signature_valid"] is True
            assert "ĐỊNH SƠN" in (detail_signed.get("signed_by") or "")

        finally:
            if draft_id:
                with service.get_connection() as conn:
                    with conn.cursor() as cur:
                        cur.execute(
                            "DELETE FROM erp_invoice_audit_logs WHERE invoice_id = %s",
                            (draft_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoice_items WHERE invoice_id = %s",
                            (draft_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoices WHERE id = %s", (draft_id,)
                        )
                        conn.commit()

    def test_api_issue_output_invoice_endpoint(self, auth_headers):
        app = create_app()
        client = TestClient(app)
        service = InvoiceProcessingService()
        created_id = None

        payload = {
            "buyer_name": "CÔNG TY CP THƯƠNG MẠI HOÀNG PHÚC",
            "buyer_tax_code": "0209998887",
            "buyer_address": "Hải Phòng",
            "buyer_email": "contact@dinhsonconstruction.com",
            "buyer_phone": "0988776655",
            "items": [
                {
                    "item_name": "Cho thuê xe cuốc Komatsu PC200 đợt 2",
                    "item_code": "TB-PC200",
                    "unit": "Ca",
                    "quantity": 10.0,
                    "unit_price_vnd": 3500000.0,
                    "vat_rate_percent": 8.0,
                    "discount_rate_percent": 5.0,  # 5% discount
                }
            ],
            "vat_rate_percent": 8.0,
            "invoice_series": "1C26TDS",
            "invoice_number": "99990002",
            "notes": "Cho thuê ca máy công trình Hoàng Phúc",
            "is_draft": False,
            "send_email_to_buyer": False,
        }

        try:
            resp = client.post(
                "/v1/erp/invoices/issue-output-invoice",
                json=payload,
                headers=auth_headers,
            )
            assert resp.status_code == 200
            data = resp.json()
            assert data["status"] == "success"
            created_id = data["invoice_id"]
            assert data["invoice_number"] == "99990002"
            # 35,000,000 - 5% disc (1,750,000) = 33,250,000 + 8% VAT (2,660,000) = 35,910,000
            assert data["total_amount_vnd"] == 35910000.0

        finally:
            if created_id:
                with service.get_connection() as conn:
                    with conn.cursor() as cur:
                        cur.execute(
                            "DELETE FROM erp_invoice_audit_logs WHERE invoice_id = %s",
                            (created_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoice_items WHERE invoice_id = %s",
                            (created_id,),
                        )
                        cur.execute(
                            "DELETE FROM erp_invoices WHERE id = %s", (created_id,)
                        )
                        conn.commit()
