from __future__ import annotations

import unittest
from datetime import UTC, date, datetime

from sqlalchemy import BigInteger, create_engine
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.orm import Session, sessionmaker


@compiles(BigInteger, "sqlite")
def _compile_bigint_for_sqlite(type_, compiler, **kw) -> str:
    _ = type_, compiler, kw
    return "INTEGER"


import app.models.master_data  # noqa: E402,F401
import app.models.miniapp  # noqa: E402,F401
import app.models.operations  # noqa: E402,F401
import app.models.org  # noqa: E402,F401
import app.models.planning  # noqa: E402,F401
import app.models.sales  # noqa: E402,F401
from app.api.routes.purchase import build_purchase_receipt_no  # noqa: E402
from app.models.base import Base  # noqa: E402
from app.models.master_data import Warehouse  # noqa: E402
from app.models.operations import PurchaseOrder, PurchaseReceipt, Supplier  # noqa: E402


class PurchaseReceiptNoGenerationTest(unittest.TestCase):
    def setUp(self) -> None:
        engine = create_engine("sqlite+pysqlite:///:memory:", future=True)
        Base.metadata.create_all(engine)
        self.SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
        self.db: Session = self.SessionLocal()
        self.supplier = Supplier(
            id=1,
            supplier_code="SUP-RECEIPT-001",
            supplier_name="入库编号供应商",
            short_name="入库编号供应商",
            lead_time_days=0,
            default_tax_rate=0,
            status="ACTIVE",
        )
        self.warehouse = Warehouse(
            id=1,
            warehouse_code="WH-RM",
            warehouse_name="原材料库",
            warehouse_type="RAW",
            status="ACTIVE",
        )
        self.order = PurchaseOrder(
            id=1,
            po_no="采购2026-00001",
            supplier_id=1,
            order_date=date.today(),
            expected_date=None,
            purchaser_employee_id=None,
            tax_rate=0,
            total_amount=0,
            status="LOCKED",
            remark=None,
        )
        self.db.add_all([self.supplier, self.warehouse, self.order])
        self.db.commit()

    def tearDown(self) -> None:
        self.db.close()

    def _add_receipt(self, receipt_no: str) -> None:
        now = datetime.now(UTC)
        self.db.add(
            PurchaseReceipt(
                receipt_no=receipt_no,
                purchase_order_id=self.order.id,
                warehouse_id=self.warehouse.id,
                receipt_date=now,
                receiver_employee_id=None,
                supplier_delivery_no=None,
                status="PENDING_QC",
                remark=None,
                created_at=now,
                updated_at=now,
            )
        )
        self.db.commit()

    def test_purchase_receipt_no_starts_from_named_year_sequence(self) -> None:
        year = date.today().strftime("%Y")

        self.assertEqual(build_purchase_receipt_no(self.db, self.order), f"入库{year}-00001")

    def test_purchase_receipt_no_increments_matching_current_year_codes(self) -> None:
        year = date.today().strftime("%Y")
        previous_year = str(int(year) - 1)
        self._add_receipt(f"入库{year}-00001")
        self._add_receipt(f"入库{year}-00009")
        self._add_receipt(f"入库{previous_year}-00099")
        self._add_receipt(f"RCV-NB-{year}0523-PO-001")

        self.assertEqual(build_purchase_receipt_no(self.db, self.order), f"入库{year}-00010")

    def test_purchase_receipt_no_ignores_malformed_same_year_codes(self) -> None:
        year = date.today().strftime("%Y")
        self._add_receipt(f"入库{year}-001")
        self._add_receipt(f"入库{year}-000001")
        self._add_receipt(f"入库{year}-ABCDE")

        self.assertEqual(build_purchase_receipt_no(self.db, self.order), f"入库{year}-00001")


if __name__ == "__main__":
    unittest.main()
