from __future__ import annotations

import unittest
from datetime import datetime

from sqlalchemy import BigInteger, create_engine, select
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.models.base import Base  # noqa: E402
from app.models.org import SystemConfig  # noqa: E402
from app.services.system_config import (  # noqa: E402
    RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE,
    get_raw_material_lot_prefix,
    normalize_raw_material_lot_prefix,
    upsert_system_config,
)


class SystemConfigRawLotPrefixTest(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()

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

    def test_raw_material_lot_prefix_defaults_and_normalizes(self) -> None:
        self.assertEqual(get_raw_material_lot_prefix(self.db), "YL")
        self.assertEqual(normalize_raw_material_lot_prefix(" yl-01 "), "YL01")
        self.assertEqual(normalize_raw_material_lot_prefix(""), "YL")
        self.assertEqual(normalize_raw_material_lot_prefix("原材料"), "YL")

    def test_upsert_raw_material_lot_prefix_normalizes_and_reads_active_config(self) -> None:
        fixed_now = datetime(2026, 6, 7, 8, 30)

        row = upsert_system_config(
            self.db,
            config_code=RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE,
            config_name="原材料库存批次号前缀",
            config_value="rm",
            remark="测试配置",
            updated_by=1,
            now=fixed_now,
        )
        self.db.commit()

        persisted = self.db.scalar(select(SystemConfig).where(SystemConfig.config_code == RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE))
        self.assertIsNotNone(persisted)
        self.assertEqual(row.config_value, "RM")
        self.assertEqual(persisted.config_value, "RM")
        self.assertEqual(persisted.config_name, "原材料库存批次号前缀")
        self.assertEqual(persisted.remark, "测试配置")
        self.assertEqual(persisted.updated_by, 1)
        self.assertEqual(persisted.updated_at, fixed_now)
        self.assertEqual(get_raw_material_lot_prefix(self.db), "RM")

        updated_now = datetime(2026, 6, 7, 9, 45)
        updated_row = upsert_system_config(
            self.db,
            config_code=RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE,
            config_name="原材料库存批次号前缀",
            config_value=" yl-02 ",
            remark="更新配置",
            updated_by=2,
            now=updated_now,
        )
        self.db.commit()

        rows = self.db.scalars(select(SystemConfig).where(SystemConfig.config_code == RAW_MATERIAL_LOT_PREFIX_CONFIG_CODE)).all()
        self.assertEqual(len(rows), 1)
        self.assertEqual(updated_row.id, persisted.id)
        self.assertEqual(rows[0].config_value, "YL02")
        self.assertEqual(rows[0].remark, "更新配置")
        self.assertEqual(rows[0].updated_by, 2)
        self.assertEqual(rows[0].updated_at, updated_now)
        self.assertEqual(get_raw_material_lot_prefix(self.db), "YL02")


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