from __future__ import annotations

import unittest

from sqlalchemy import create_engine, select, text
from sqlalchemy.orm import Session, sessionmaker


import app.models  # noqa: E402,F401
from app.models.base import Base  # noqa: E402
from app.models.master_data import Warehouse  # noqa: E402
from app.models.miniapp import MiniAppPersonAttendancePoint, MiniAppPersonnel, MiniAppPersonRole  # noqa: E402
from app.models.operations import WarehouseLocation  # noqa: E402
from app.models.org import AiAssistantConfig, Department, Employee, Permission, Role, RolePermission, SystemConfig, User, UserRole  # noqa: E402
from app.services.auth import verify_password  # noqa: E402
from app.services.system_permissions import MENU_PERMISSION_TREE  # noqa: E402


class SystemInitializerSeedTest(unittest.TestCase):
    def test_table_groups_have_no_duplicates_and_include_expected_tables(self) -> None:
        from app.services.system_initializer import (
            ACCOUNT_RESET_TABLES,
            BUSINESS_RESET_TABLES,
            MINIAPP_RESET_TABLES,
            RESET_TABLES_IN_DELETE_ORDER,
            SKELETON_TABLES,
        )

        all_tables = BUSINESS_RESET_TABLES + MINIAPP_RESET_TABLES + ACCOUNT_RESET_TABLES + SKELETON_TABLES
        reset_tables = BUSINESS_RESET_TABLES + MINIAPP_RESET_TABLES + ACCOUNT_RESET_TABLES

        self.assertEqual(len(all_tables), len(set(all_tables)))
        self.assertEqual(set(reset_tables).issubset(set(RESET_TABLES_IN_DELETE_ORDER)), True)
        self.assertEqual(len(RESET_TABLES_IN_DELETE_ORDER), len(set(RESET_TABLES_IN_DELETE_ORDER)))
        self.assertIn("so_sales_order", BUSINESS_RESET_TABLES)
        self.assertIn("wh_stock_lot", BUSINESS_RESET_TABLES)
        self.assertIn("pp_production_batch_ledger", BUSINESS_RESET_TABLES)
        self.assertIn("production_reports", MINIAPP_RESET_TABLES)
        self.assertIn("work_sessions", MINIAPP_RESET_TABLES)
        self.assertIn("sys_user", ACCOUNT_RESET_TABLES)
        self.assertIn("sys_permission", SKELETON_TABLES)
        self.assertIn("wh_warehouse", SKELETON_TABLES)


class SystemInitializerSkeletonSeedTest(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_seed_system_skeleton_creates_required_defaults(self) -> None:
        from app.services.system_initializer import SystemInitializeOptions, seed_system_skeleton

        options = SystemInitializeOptions(
            mode="reset",
            company_name="百华",
            admin_name="超级管理员",
            admin_phone="13800000000",
            admin_password="secret123",
            smart_operation_report_enabled=False,
            confirm_reset=True,
        )

        result = seed_system_skeleton(self.db, options)
        self.db.commit()

        admin_user = self.db.scalar(select(User).where(User.username == "13800000000"))
        self.assertIsNotNone(admin_user)
        assert admin_user is not None
        self.assertEqual(admin_user.is_super_admin, 1)
        self.assertTrue(verify_password("secret123", admin_user.password_hash))

        admin_employee = self.db.scalar(select(Employee).where(Employee.mobile == "13800000000"))
        self.assertIsNotNone(admin_employee)
        assert admin_employee is not None
        self.assertEqual(admin_employee.employee_name, "超级管理员")

        root = self.db.scalar(select(Department).where(Department.dept_code == "ORG_ROOT"))
        self.assertIsNotNone(root)
        assert root is not None
        self.assertEqual(root.dept_name, "百华")

        expected_permission_codes = set()

        def walk(nodes: list[tuple[str, str, list]]) -> None:
            for code, _name, children in nodes:
                expected_permission_codes.add(code)
                walk(children)

        walk(MENU_PERMISSION_TREE)
        actual_permission_codes = set(self.db.scalars(select(Permission.permission_code)).all())
        self.assertEqual(expected_permission_codes, actual_permission_codes)

        admin_role = self.db.scalar(select(Role).where(Role.role_code == "ADMIN"))
        self.assertIsNotNone(admin_role)
        assert admin_role is not None
        self.assertEqual(
            self.db.query(RolePermission).filter(RolePermission.role_id == admin_role.id).count(),
            len(expected_permission_codes),
        )
        role_names = {role.role_code: role.role_name for role in self.db.scalars(select(Role)).all()}
        self.assertEqual(
            role_names,
            {
                "ADMIN": "超级管理员",
                "PURCHASER": "采购专员",
                "WAREHOUSE": "仓库管理人员",
                "SALES": "销售人员",
            },
        )
        self.assertEqual(self.db.query(UserRole).count(), 1)

        self.assertEqual(self.db.query(Warehouse).count(), 6)
        self.assertEqual(self.db.query(WarehouseLocation).count(), 6)
        self.assertEqual({row.warehouse_type for row in self.db.scalars(select(Warehouse)).all()}, {"RAW", "SEMI", "FINISHED", "AUX", "SCRAP", "RETURN"})
        self.assertEqual(self.db.query(WarehouseLocation).filter(WarehouseLocation.is_default == 1).count(), 6)

        prefix = self.db.scalar(select(SystemConfig).where(SystemConfig.config_code == "RAW_MATERIAL_LOT_PREFIX"))
        self.assertIsNotNone(prefix)
        assert prefix is not None
        self.assertEqual(prefix.config_value, "YL")
        smart = self.db.scalar(select(SystemConfig).where(SystemConfig.config_code == "SMART_OPERATION_REPORT_ENABLED"))
        self.assertIsNotNone(smart)
        assert smart is not None
        self.assertEqual(smart.config_value, "关闭")
        ai_config = self.db.scalar(select(AiAssistantConfig))
        self.assertIsNotNone(ai_config)
        assert ai_config is not None
        self.assertEqual(ai_config.assistant_name, "百华工艺助手")

        units = dict(self.db.execute(text("SELECT unit_code, unit_name FROM md_unit")).all())
        self.assertEqual(units, {"KG": "kg", "PCS": "件", "SET": "套"})
        categories = dict(self.db.execute(text("SELECT category_code, category_name FROM md_item_category")).all())
        self.assertEqual(categories, {"RAW": "原材料", "SEMI": "半成品", "FINISHED": "成品", "AUX": "辅料", "SCRAP": "废料"})

        miniapp_admin = self.db.get(MiniAppPersonnel, "13800000000")
        self.assertIsNotNone(miniapp_admin)
        assert miniapp_admin is not None
        self.assertEqual(miniapp_admin.name, "超级管理员")
        self.assertIsNotNone(self.db.get(MiniAppPersonRole, {"phone": "13800000000", "role": "admin"}))
        self.assertIsNotNone(
            self.db.get(
                MiniAppPersonAttendancePoint,
                {"phone": "13800000000", "attendance_point_name": "百华"},
            )
        )

        self.assertEqual(result.seeded["warehouse_count"], 6)
        self.assertEqual(result.seeded["admin_username"], "13800000000")

    def test_seed_system_skeleton_defaults_smart_operation_report_to_enabled(self) -> None:
        from app.services.system_initializer import SystemInitializeOptions, seed_system_skeleton

        options = SystemInitializeOptions(
            mode="fresh",
            company_name="百华",
            admin_name="超级管理员",
            admin_phone="13800000000",
            admin_password="secret123",
        )

        result = seed_system_skeleton(self.db, options)
        self.db.commit()

        smart = self.db.scalar(select(SystemConfig).where(SystemConfig.config_code == "SMART_OPERATION_REPORT_ENABLED"))
        self.assertIsNotNone(smart)
        assert smart is not None
        self.assertEqual(smart.config_value, "开启")
        self.assertEqual(result.seeded["smart_operation_report_enabled"], True)


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