from __future__ import annotations

import json
import importlib
import pkgutil
import shutil
import subprocess
import tempfile
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Iterable

import app.models  # noqa: F401
from sqlalchemy import create_engine, func, inspect, select, text
from sqlalchemy.engine import Engine, URL
from sqlalchemy.orm import Session

import app.models as models_package
from app.models.base import Base
from app.models.master_data import ItemCategory, Unit, Warehouse
from app.models.operations import WarehouseLocation
from app.models.org import AiAssistantConfig, Department, Employee, Permission, Role, RolePermission, SystemConfig, User, UserRole
from app.services.auth import hash_password
from app.services.system_permissions import MENU_PERMISSION_TREE


BUSINESS_RESET_TABLES = [
    "pp_scrap_record",
    "po_receipt_item",
    "po_purchase_return_item",
    "rt_return_disposition",
    "pp_work_order_material_issue",
    "pp_operation_report",
    "pp_material_issue_item",
    "pp_completion_receipt_item",
    "po_purchase_order_item",
    "wh_stocktake_adjustment",
    "wh_special_adjustment_line",
    "rt_return_item",
    "pp_work_order_operation",
    "pp_work_order_material",
    "pp_production_batch_ledger_txn",
    "pp_material_issue",
    "pp_completion_receipt",
    "mrp_material_demand",
    "fi_cost_allocation",
    "em_maintenance_order",
    "wh_stocktake_line",
    "wh_inventory_txn",
    "so_delivery_item",
    "rt_return_order",
    "pp_work_order",
    "pp_production_batch_ledger",
    "md_process_route_operation",
    "md_bom_item",
    "em_maintenance_plan",
    "wh_stock_lot",
    "wh_stock_balance",
    "wh_special_adjustment",
    "sys_broadcast_message",
    "so_sales_order_item",
    "so_delivery",
    "po_receipt",
    "po_purchase_return",
    "po_purchase_order_sales_order",
    "md_product",
    "md_process_route",
    "md_material",
    "md_bom",
    "fi_statement_snapshot",
    "fi_overhead_entry",
    "em_equipment",
    "wh_stocktake_warehouse",
    "so_sales_order",
    "po_purchase_order",
    "md_work_center",
    "md_item",
    "wh_stocktake",
    "md_supplier",
    "md_process",
    "md_customer",
    "fi_accounting_period",
    "document_archives",
]

MINIAPP_RESET_TABLES = [
    "report_audit_logs",
    "production_report_items",
    "mold_lock_feedbacks",
    "work_session_devices",
    "production_reports",
    "notice_points",
    "work_sessions",
    "person_roles",
    "person_attendance_points",
    "notices",
    "device_qrcodes",
    "device_qrcode_batch_tasks",
    "work_schedules",
    "reconciliation_ledger_entries",
    "products",
    "personnel",
    "equipment",
    "attendance_points",
]

ACCOUNT_RESET_TABLES = [
    "sys_user_role",
    "sys_user",
    "sys_org_manager_binding",
    "sys_org_employee_binding",
    "sys_department",
    "hr_employee",
]

SKELETON_TABLES = [
    "sys_ai_assistant_config",
    "wh_location",
    "sys_role_permission",
    "wh_warehouse",
    "sys_system_config",
    "sys_role",
    "sys_permission",
    "md_unit",
    "md_item_category",
]

PRE_DELETE_NULLABLE_FKS = {
    "hr_employee": ["manager_employee_id"],
    "sys_department": ["manager_employee_id"],
}

RESET_TABLES_IN_DELETE_ORDER = [
    "pp_scrap_record",
    "po_receipt_item",
    "po_purchase_return_item",
    "rt_return_disposition",
    "pp_work_order_material_issue",
    "pp_operation_report",
    "pp_material_issue_item",
    "pp_completion_receipt_item",
    "po_purchase_order_item",
    "wh_stocktake_adjustment",
    "wh_special_adjustment_line",
    "rt_return_item",
    "pp_work_order_operation",
    "pp_work_order_material",
    "pp_production_batch_ledger_txn",
    "pp_material_issue",
    "pp_completion_receipt",
    "mrp_material_demand",
    "fi_cost_allocation",
    "em_maintenance_order",
    "wh_stocktake_line",
    "wh_inventory_txn",
    "so_delivery_item",
    "rt_return_order",
    "report_audit_logs",
    "production_report_items",
    "pp_work_order",
    "pp_production_batch_ledger",
    "mold_lock_feedbacks",
    "md_process_route_operation",
    "md_bom_item",
    "em_maintenance_plan",
    "work_session_devices",
    "wh_stock_lot",
    "wh_stock_balance",
    "wh_special_adjustment",
    "sys_user_role",
    "sys_broadcast_message",
    "sys_ai_assistant_config",
    "so_sales_order_item",
    "so_delivery",
    "production_reports",
    "po_receipt",
    "po_purchase_return",
    "po_purchase_order_sales_order",
    "notice_points",
    "md_product",
    "md_process_route",
    "md_material",
    "md_bom",
    "fi_statement_snapshot",
    "fi_overhead_entry",
    "em_equipment",
    "work_sessions",
    "wh_stocktake_warehouse",
    "wh_location",
    "sys_user",
    "sys_role_permission",
    "sys_org_manager_binding",
    "sys_org_employee_binding",
    "so_sales_order",
    "po_purchase_order",
    "person_roles",
    "person_attendance_points",
    "notices",
    "md_work_center",
    "md_item",
    "device_qrcodes",
    "device_qrcode_batch_tasks",
    "work_schedules",
    "wh_warehouse",
    "wh_stocktake",
    "sys_system_config",
    "sys_role",
    "sys_permission",
    "reconciliation_ledger_entries",
    "products",
    "personnel",
    "md_unit",
    "md_supplier",
    "md_process",
    "md_item_category",
    "md_customer",
    "hr_employee",
    "sys_department",
    "fi_accounting_period",
    "equipment",
    "document_archives",
    "attendance_points",
]

WAREHOUSE_TYPES = [
    ("RAW", "原材料库", "原材料默认库位"),
    ("SEMI", "半成品库", "半成品默认库位"),
    ("FINISHED", "成品库", "成品默认库位"),
    ("AUX", "辅料库", "辅料默认库位"),
    ("SCRAP", "废料库", "废料默认库位"),
    ("RETURN", "退货库", "退货默认库位"),
]


@dataclass(frozen=True)
class SystemInitializeOptions:
    mode: str
    company_name: str
    admin_name: str
    admin_phone: str
    admin_password: str
    smart_operation_report_enabled: bool = True
    confirm_reset: bool = False
    delete_files: bool = False
    allow_any_database: bool = False


@dataclass(frozen=True)
class SystemInitializeResult:
    mode: str
    database: str = ""
    backup_path: str | None = None
    summary_path: str | None = None
    counts_before: dict[str, int] = field(default_factory=dict)
    counts_after: dict[str, int] = field(default_factory=dict)
    seeded: dict[str, int | str | bool] = field(default_factory=dict)


def _now() -> datetime:
    return datetime.now().replace(microsecond=0)


def _flatten_menu_permissions(nodes: list[tuple[str, str, list]]) -> list[tuple[str, str]]:
    result: list[tuple[str, str]] = []
    for code, name, children in nodes:
        result.append((code, name))
        result.extend(_flatten_menu_permissions(children))
    return result


def _is_sqlite(db: Session) -> bool:
    bind = db.get_bind()
    return bool(bind and bind.dialect.name == "sqlite")


def _is_mysql(db: Session) -> bool:
    bind = db.get_bind()
    return bool(bind and bind.dialect.name in {"mysql", "mariadb"})


def _quote_table_name(table_name: str) -> str:
    if not table_name.replace("_", "").isalnum():
        raise ValueError(f"Unsafe table name: {table_name}")
    return f"`{table_name}`"


def _existing_tables(db: Session, table_names: Iterable[str]) -> set[str]:
    connection = db.connection()
    if connection is None:
        return set()
    existing = set(inspect(connection).get_table_names())
    return {table_name for table_name in table_names if table_name in existing}


def _count_table(db: Session, table_name: str) -> int:
    return int(db.execute(text(f"SELECT COUNT(*) FROM {_quote_table_name(table_name)}")).scalar_one() or 0)


def count_existing_tables(db: Session, table_names: Iterable[str]) -> dict[str, int]:
    db.flush()
    existing = _existing_tables(db, table_names)
    return {table_name: _count_table(db, table_name) for table_name in table_names if table_name in existing}


def _sqlite_has_sequence_table(db: Session) -> bool:
    return bool(
        db.execute(
            text(
                """
                SELECT name
                FROM sqlite_master
                WHERE type = 'table' AND name = 'sqlite_sequence'
                """
            )
        ).first()
    )


def _reset_sqlite_sequences(db: Session, table_names: Iterable[str]) -> None:
    if not _sqlite_has_sequence_table(db):
        return
    for table_name in table_names:
        db.execute(text("DELETE FROM sqlite_sequence WHERE name = :table_name"), {"table_name": table_name})


def _nullify_pre_delete_foreign_keys(db: Session, table_names: Iterable[str], existing_tables: set[str]) -> None:
    for table_name in table_names:
        columns = PRE_DELETE_NULLABLE_FKS.get(table_name, [])
        if not columns or table_name not in existing_tables:
            continue
        assignments = ", ".join(f"{column_name} = NULL" for column_name in columns)
        db.execute(text(f"UPDATE {_quote_table_name(table_name)} SET {assignments}"))


def _clear_tables(db: Session, table_names: Iterable[str]) -> None:
    db.flush()
    existing = _existing_tables(db, table_names)
    tables_to_clear = [table_name for table_name in table_names if table_name in existing]
    if not tables_to_clear:
        return

    if _is_mysql(db):
        db.execute(text("SET FOREIGN_KEY_CHECKS = 0"))

    try:
        _nullify_pre_delete_foreign_keys(db, tables_to_clear, existing)
        for table_name in tables_to_clear:
            db.execute(text(f"DELETE FROM {_quote_table_name(table_name)}"))
        if _is_sqlite(db):
            _reset_sqlite_sequences(db, tables_to_clear)
    finally:
        if _is_mysql(db):
            db.execute(text("SET FOREIGN_KEY_CHECKS = 1"))


def _summary_table_names() -> list[str]:
    return list(RESET_TABLES_IN_DELETE_ORDER)


def _add_seed_row(db: Session, row: object) -> object:
    """SQLite does not autoincrement BIGINT PKs; MySQL still uses native AUTO_INCREMENT."""
    if _is_sqlite(db) and getattr(row, "id", None) is None and hasattr(row, "__table__"):
        primary_keys = list(row.__table__.primary_key.columns)
        if len(primary_keys) == 1 and primary_keys[0].name == "id":
            database_max = int(db.execute(select(func.coalesce(func.max(primary_keys[0]), 0)).select_from(row.__table__)).scalar_one() or 0)
            pending_max = max(
                (
                    int(pending_id)
                    for pending in db.new
                    if getattr(pending, "__table__", None) is row.__table__
                    and (pending_id := getattr(pending, "id", None)) is not None
                ),
                default=0,
            )
            setattr(row, "id", max(database_max, pending_max) + 1)
    db.add(row)
    return row


def _upsert_system_config(db: Session, *, code: str, name: str, value: str, remark: str) -> None:
    now = _now()
    row = db.scalar(select(SystemConfig).where(SystemConfig.config_code == code))
    if row is None:
        _add_seed_row(
            db,
            SystemConfig(
                config_code=code,
                config_name=name,
                config_value=value,
                remark=remark,
                status="ACTIVE",
                created_by=None,
                updated_by=None,
                created_at=now,
                updated_at=now,
            ),
        )
        return
    row.config_name = name
    row.config_value = value
    row.remark = remark
    row.status = "ACTIVE"
    row.updated_at = now


def _upsert_role(db: Session, role_code: str, role_name: str) -> Role:
    now = _now()
    row = db.scalar(select(Role).where(Role.role_code == role_code))
    if row is None:
        row = Role(
            role_code=role_code,
            role_name=role_name,
            role_scope="SYSTEM",
            status="ACTIVE",
            remark="系统初始化内置角色",
            created_at=now,
            updated_at=now,
        )
        _add_seed_row(db, row)
        db.flush()
        return row
    row.role_name = role_name
    row.role_scope = "SYSTEM"
    row.status = "ACTIVE"
    row.remark = "系统初始化内置角色"
    row.updated_at = now
    db.flush()
    return row


def _seed_permissions_and_roles(db: Session) -> dict[str, int]:
    now = _now()
    role_defs = [
        ("ADMIN", "超级管理员"),
        ("PURCHASER", "采购专员"),
        ("WAREHOUSE", "仓库管理人员"),
        ("SALES", "销售人员"),
    ]
    roles = [_upsert_role(db, code, name) for code, name in role_defs]
    permissions: list[Permission] = []
    for code, name in _flatten_menu_permissions(MENU_PERMISSION_TREE):
        permission = db.scalar(select(Permission).where(Permission.permission_code == code))
        if permission is None:
            permission = Permission(
                permission_code=code,
                permission_name=name,
                module_code=code.replace("MENU_", ""),
                action_code="VIEW",
                status="ACTIVE",
                created_at=now,
                updated_at=now,
            )
            _add_seed_row(db, permission)
            db.flush()
        else:
            permission.permission_name = name
            permission.module_code = code.replace("MENU_", "")
            permission.action_code = "VIEW"
            permission.status = "ACTIVE"
            permission.updated_at = now
            db.flush()
        permissions.append(permission)

    admin_role = roles[0]
    for permission in permissions:
        existing = db.scalar(
            select(RolePermission).where(
                RolePermission.role_id == admin_role.id,
                RolePermission.permission_id == permission.id,
            )
        )
        if existing is None:
            _add_seed_row(db, RolePermission(role_id=admin_role.id, permission_id=permission.id, created_at=now))
    return {"role_count": len(role_defs), "permission_count": len(permissions)}


def _seed_system_configs(db: Session, options: SystemInitializeOptions) -> None:
    _upsert_system_config(
        db,
        code="RAW_MATERIAL_LOT_PREFIX",
        name="原材料库存批次前缀",
        value="YL",
        remark="系统初始化默认值",
    )
    _upsert_system_config(
        db,
        code="SMART_OPERATION_REPORT_ENABLED",
        name="对接智能报工小程序",
        value="开启" if options.smart_operation_report_enabled else "关闭",
        remark="系统初始化默认值",
    )


def _seed_units_and_categories(db: Session) -> dict[str, int]:
    now = _now()
    unit_defs = [
        ("KG", "kg", 3),
        ("PCS", "件", 0),
        ("SET", "套", 0),
    ]
    for code, name, precision in unit_defs:
        unit = db.scalar(select(Unit).where(Unit.unit_code == code))
        if unit is None:
            _add_seed_row(db, Unit(unit_code=code, unit_name=name, precision_digits=precision, created_at=now, updated_at=now))
        else:
            unit.unit_name = name
            unit.precision_digits = precision
            unit.updated_at = now

    category_defs = [
        ("RAW", "原材料", "RAW_MATERIAL"),
        ("SEMI", "半成品", "SEMI_FINISHED"),
        ("FINISHED", "成品", "FINISHED_GOOD"),
        ("AUX", "辅料", "AUXILIARY"),
        ("SCRAP", "废料", "SCRAP"),
    ]
    for code, name, item_type in category_defs:
        category = db.scalar(select(ItemCategory).where(ItemCategory.category_code == code))
        if category is None:
            _add_seed_row(
                db,
                ItemCategory(
                    category_code=code,
                    category_name=name,
                    parent_id=None,
                    item_type=item_type,
                    sort_no=0,
                    status="ACTIVE",
                    created_at=now,
                    updated_at=now,
                ),
            )
        else:
            category.category_name = name
            category.item_type = item_type
            category.status = "ACTIVE"
            category.updated_at = now
    return {"unit_count": len(unit_defs), "category_count": len(category_defs)}


def _seed_warehouses(db: Session) -> dict[str, int]:
    now = _now()
    for warehouse_type, warehouse_name, location_name in WAREHOUSE_TYPES:
        warehouse = db.scalar(select(Warehouse).where(Warehouse.warehouse_type == warehouse_type))
        if warehouse is None:
            warehouse = Warehouse(
                warehouse_code=f"WH_{warehouse_type}",
                warehouse_name=warehouse_name,
                warehouse_type=warehouse_type,
                manager_employee_id=None,
                status="ACTIVE",
                remark="系统初始化默认仓库",
                created_at=now,
                updated_at=now,
            )
            _add_seed_row(db, warehouse)
            db.flush()
        else:
            warehouse.warehouse_code = f"WH_{warehouse_type}"
            warehouse.warehouse_name = warehouse_name
            warehouse.status = "ACTIVE"
            warehouse.updated_at = now
            db.flush()

        location = db.scalar(
            select(WarehouseLocation).where(
                WarehouseLocation.warehouse_id == warehouse.id,
                WarehouseLocation.location_code == f"LOC_{warehouse_type}",
            )
        )
        if location is None:
            _add_seed_row(
                db,
                WarehouseLocation(
                    warehouse_id=warehouse.id,
                    location_code=f"LOC_{warehouse_type}",
                    location_name=location_name,
                    zone_name=None,
                    is_default=1,
                    is_locked=0,
                    status="ACTIVE",
                    remark="系统初始化默认库位",
                    created_at=now,
                    updated_at=now,
                ),
            )
        else:
            location.location_name = location_name
            location.is_default = 1
            location.is_locked = 0
            location.status = "ACTIVE"
            location.updated_at = now
    return {"warehouse_count": len(WAREHOUSE_TYPES), "location_count": len(WAREHOUSE_TYPES)}


def _seed_admin_user(db: Session, options: SystemInitializeOptions) -> dict[str, int | str]:
    now = _now()
    root = db.scalar(select(Department).where(Department.dept_code == "ORG_ROOT"))
    if root is None:
        root = Department(
            dept_code="ORG_ROOT",
            dept_name=options.company_name,
            parent_id=None,
            org_node_type="COMPANY",
            dept_type="ADMIN",
            manager_name=None,
            manager_employee_id=None,
            status="ACTIVE",
            sort_no=0,
            remark="系统初始化根组织",
            created_at=now,
            updated_at=now,
        )
        _add_seed_row(db, root)
        db.flush()
    else:
        root.dept_name = options.company_name
        root.org_node_type = "COMPANY"
        root.dept_type = "ADMIN"
        root.status = "ACTIVE"
        root.updated_at = now
        db.flush()

    employee = db.scalar(select(Employee).where(Employee.employee_code == "EMP_ADMIN"))
    if employee is None:
        employee = Employee(
            employee_code="EMP_ADMIN",
            employee_name=options.admin_name,
            dept_id=root.id,
            mobile=options.admin_phone,
            gender=None,
            hire_date=None,
            job_title="超级管理员",
            shift_code=None,
            manager_employee_id=None,
            is_operator=0,
            is_workshop_staff=0,
            status="ACTIVE",
            remark="系统初始化超级管理员",
            created_at=now,
            updated_at=now,
        )
        _add_seed_row(db, employee)
        db.flush()
    else:
        employee.employee_name = options.admin_name
        employee.dept_id = root.id
        employee.mobile = options.admin_phone
        employee.status = "ACTIVE"
        employee.updated_at = now
        db.flush()

    user = db.scalar(select(User).where(User.username == options.admin_phone))
    if user is None:
        user = User(
            username=options.admin_phone,
            password_hash=hash_password(options.admin_password),
            employee_id=employee.id,
            dept_id=root.id,
            nickname=options.admin_name,
            email=None,
            is_super_admin=1,
            last_login_at=None,
            status="ACTIVE",
            created_at=now,
            updated_at=now,
        )
        _add_seed_row(db, user)
        db.flush()
    else:
        user.password_hash = hash_password(options.admin_password)
        user.employee_id = employee.id
        user.dept_id = root.id
        user.nickname = options.admin_name
        user.is_super_admin = 1
        user.status = "ACTIVE"
        user.updated_at = now
        db.flush()

    admin_role = db.scalar(select(Role).where(Role.role_code == "ADMIN"))
    if admin_role is not None:
        existing = db.scalar(select(UserRole).where(UserRole.user_id == user.id, UserRole.role_id == admin_role.id))
        if existing is None:
            _add_seed_row(db, UserRole(user_id=user.id, role_id=admin_role.id, created_at=now))
    return {"admin_user_id": user.id, "admin_username": user.username}


def _seed_ai_assistant_config(db: Session, options: SystemInitializeOptions, admin_user_id: int | None) -> dict[str, int | str]:
    now = _now()
    row = db.scalar(select(AiAssistantConfig).order_by(AiAssistantConfig.id.asc()))
    assistant_name = f"{options.company_name}工艺助手"
    if row is None:
        row = AiAssistantConfig(
            assistant_name=assistant_name,
            provider_name=None,
            api_base_url=None,
            api_key=None,
            model_name=None,
            temperature=0.3,
            system_prompt=None,
            enabled=0,
            created_by=admin_user_id,
            updated_by=admin_user_id,
            created_at=now,
            updated_at=now,
        )
        _add_seed_row(db, row)
        db.flush()
    else:
        row.assistant_name = assistant_name
        row.updated_by = admin_user_id
        row.updated_at = now
        db.flush()
    return {"ai_assistant_config_count": 1, "ai_assistant_name": assistant_name}


def _seed_miniapp_defaults(db: Session, options: SystemInitializeOptions) -> dict[str, int]:
    now = _now()
    point = db.execute(text("SELECT name FROM attendance_points WHERE name = :name"), {"name": options.company_name}).first()
    if point is None:
        db.execute(
            text(
                """
                INSERT INTO attendance_points
                    (name, latitude, longitude, radius_meters, remark, is_active, created_at, updated_at)
                VALUES
                    (:name, NULL, NULL, 500, '系统初始化默认考勤点', 1, :now, :now)
                """
            ),
            {"name": options.company_name, "now": now},
        )
    else:
        db.execute(
            text(
                """
                UPDATE attendance_points
                SET remark = '系统初始化默认考勤点', is_active = 1, updated_at = :now
                WHERE name = :name
                """
            ),
            {"name": options.company_name, "now": now},
        )

    person = db.execute(text("SELECT phone FROM personnel WHERE phone = :phone"), {"phone": options.admin_phone}).first()
    if person is None:
        db.execute(
            text(
                """
                INSERT INTO personnel (phone, name, is_temporary, temporary_expires_at, created_at, updated_at)
                VALUES (:phone, :name, 0, NULL, :now, :now)
                """
            ),
            {"phone": options.admin_phone, "name": options.admin_name, "now": now},
        )
    else:
        db.execute(
            text(
                """
                UPDATE personnel
                SET name = :name, is_temporary = 0, temporary_expires_at = NULL, updated_at = :now
                WHERE phone = :phone
                """
            ),
            {"phone": options.admin_phone, "name": options.admin_name, "now": now},
        )

    role = db.execute(
        text("SELECT phone FROM person_roles WHERE phone = :phone AND role = 'admin'"),
        {"phone": options.admin_phone},
    ).first()
    if role is None:
        db.execute(
            text("INSERT INTO person_roles (phone, role, created_at) VALUES (:phone, 'admin', :now)"),
            {"phone": options.admin_phone, "now": now},
        )

    binding = db.execute(
        text(
            """
            SELECT phone
            FROM person_attendance_points
            WHERE phone = :phone AND attendance_point_name = :point
            """
        ),
        {"phone": options.admin_phone, "point": options.company_name},
    ).first()
    if binding is None:
        db.execute(
            text(
                """
                INSERT INTO person_attendance_points (phone, attendance_point_name, created_at)
                VALUES (:phone, :point, :now)
                """
            ),
            {"phone": options.admin_phone, "point": options.company_name, "now": now},
        )
    return {"miniapp_attendance_point_count": 1, "miniapp_admin_count": 1}


def seed_system_skeleton(db: Session, options: SystemInitializeOptions) -> SystemInitializeResult:
    permission_summary = _seed_permissions_and_roles(db)
    _seed_system_configs(db, options)
    unit_summary = _seed_units_and_categories(db)
    warehouse_summary = _seed_warehouses(db)
    admin_summary = _seed_admin_user(db, options)
    ai_summary = _seed_ai_assistant_config(db, options, int(admin_summary["admin_user_id"]) if admin_summary.get("admin_user_id") else None)
    miniapp_summary = _seed_miniapp_defaults(db, options)

    return SystemInitializeResult(
        mode=options.mode,
        seeded={
            **permission_summary,
            **unit_summary,
            **warehouse_summary,
            **admin_summary,
            **ai_summary,
            **miniapp_summary,
            "smart_operation_report_enabled": options.smart_operation_report_enabled,
        },
    )


def reset_existing_database(db: Session, options: SystemInitializeOptions) -> SystemInitializeResult:
    if not options.confirm_reset:
        raise ValueError("Refusing to reset database without --confirm-reset")

    table_names = _summary_table_names()
    counts_before = count_existing_tables(db, table_names)
    _clear_tables(db, table_names)
    seeded_result = seed_system_skeleton(db, options)
    db.flush()
    counts_after = count_existing_tables(db, table_names)

    return SystemInitializeResult(
        mode="reset",
        counts_before=counts_before,
        counts_after=counts_after,
        seeded=seeded_result.seeded,
    )


def create_all_schema_tables(engine: Engine) -> None:
    for module_info in pkgutil.iter_modules(models_package.__path__):
        if module_info.name.startswith("_"):
            continue
        importlib.import_module(f"{models_package.__name__}.{module_info.name}")
    Base.metadata.create_all(engine)


def fresh_initialize_database(engine: Engine, options: SystemInitializeOptions) -> SystemInitializeResult:
    create_all_schema_tables(engine)
    fresh_options = SystemInitializeOptions(
        mode="fresh",
        company_name=options.company_name,
        admin_name=options.admin_name,
        admin_phone=options.admin_phone,
        admin_password=options.admin_password,
        smart_operation_report_enabled=options.smart_operation_report_enabled,
        confirm_reset=options.confirm_reset,
        delete_files=options.delete_files,
        allow_any_database=options.allow_any_database,
    )
    with Session(engine, future=True) as db:
        seeded_result = seed_system_skeleton(db, fresh_options)
        db.flush()
        counts_after = count_existing_tables(db, _summary_table_names())
        db.commit()

    return SystemInitializeResult(
        mode="fresh",
        counts_after=counts_after,
        seeded=seeded_result.seeded,
    )


def _mysql_url_from_settings(settings: object, *, include_database: bool) -> URL:
    dsn = getattr(settings, "mysql_dsn", None)
    if isinstance(dsn, URL):
        return dsn.set(database=getattr(settings, "mysql_database", None) if include_database else None)
    return URL.create(
        "mysql+pymysql",
        username=getattr(settings, "mysql_user"),
        password=getattr(settings, "mysql_password"),
        host=getattr(settings, "mysql_host"),
        port=getattr(settings, "mysql_port"),
        database=getattr(settings, "mysql_database") if include_database else None,
    )


def create_database_if_missing(settings: object) -> str:
    database = str(getattr(settings, "mysql_database"))
    server_url = _mysql_url_from_settings(settings, include_database=False)
    engine = create_engine(server_url, isolation_level="AUTOCOMMIT", future=True)
    try:
        with engine.connect() as conn:
            conn.execute(
                text(
                    f"CREATE DATABASE IF NOT EXISTS {_quote_table_name(database)} "
                    "CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
                )
            )
    finally:
        engine.dispose()
    return database


def write_summary_report(output_dir: str | Path, result: SystemInitializeResult) -> str:
    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)
    created_at = _now().isoformat()
    summary_path = output / f"system_init_summary_{created_at.replace(':', '').replace('-', '')}.json"
    payload = {
        "mode": result.mode,
        "database": result.database,
        "backup_path": result.backup_path,
        "summary_path": str(summary_path),
        "counts_before": result.counts_before,
        "counts_after": result.counts_after,
        "seeded": result.seeded,
        "created_at": created_at,
    }
    summary_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True), encoding="utf-8")
    return str(summary_path)


def default_output_dir() -> Path:
    return Path(__file__).resolve().parents[3] / "outputs" / "cleanup_backups"


def backup_mysql_database(settings: object, output_dir: str | Path) -> str:
    output = Path(output_dir)
    output.mkdir(parents=True, exist_ok=True)
    timestamp = _now().strftime("%Y%m%d_%H%M%S")
    backup_path = output / f"system_init_backup_{timestamp}.sql"
    database = str(getattr(settings, "mysql_database"))
    password = str(getattr(settings, "mysql_password", "") or "")
    with tempfile.NamedTemporaryFile("w", encoding="utf-8", delete=False) as defaults_file:
        defaults_path = Path(defaults_file.name)
        defaults_file.write("[client]\n")
        defaults_file.write(f"host={getattr(settings, 'mysql_host')}\n")
        defaults_file.write(f"port={getattr(settings, 'mysql_port')}\n")
        defaults_file.write(f"user={getattr(settings, 'mysql_user')}\n")
        if password:
            defaults_file.write(f"password={password}\n")
    defaults_path.chmod(0o600)
    command = [
        "mysqldump",
        f"--defaults-extra-file={defaults_path}",
        f"--result-file={backup_path}",
        "--single-transaction",
        "--no-tablespaces",
        "--routines",
        "--triggers",
        database,
    ]
    try:
        subprocess.run(command, check=True)
    finally:
        defaults_path.unlink(missing_ok=True)
    return str(backup_path)


def delete_managed_files(directories: Iterable[Path]) -> dict[str, int]:
    def count_tree(path: Path) -> tuple[int, int]:
        if path.is_file() or path.is_symlink():
            return 1, 0
        file_count = 0
        dir_count = 1
        for nested in path.iterdir():
            nested_file_count, nested_dir_count = count_tree(nested)
            file_count += nested_file_count
            dir_count += nested_dir_count
        return file_count, dir_count

    deleted_file_count = 0
    deleted_dir_count = 0
    for directory in directories:
        if not directory.exists() or not directory.is_dir():
            continue
        for child in directory.iterdir():
            if child.is_file() or child.is_symlink():
                child.unlink()
                deleted_file_count += 1
            elif child.is_dir():
                nested_file_count, nested_dir_count = count_tree(child)
                shutil.rmtree(child)
                deleted_file_count += nested_file_count
                deleted_dir_count += nested_dir_count
    return {"deleted_file_count": deleted_file_count, "deleted_dir_count": deleted_dir_count}


def reset_existing_database_with_backup(
    engine: Engine,
    settings: object,
    options: SystemInitializeOptions,
    output_dir: str | Path | None = None,
) -> SystemInitializeResult:
    output = Path(output_dir) if output_dir is not None else default_output_dir()
    backup_path = backup_mysql_database(settings, output)
    database = str(getattr(settings, "mysql_database", ""))

    with Session(engine, future=True) as db:
        reset_result = reset_existing_database(db, options)
        db.commit()

    result = SystemInitializeResult(
        mode=reset_result.mode,
        database=database,
        backup_path=backup_path,
        counts_before=reset_result.counts_before,
        counts_after=reset_result.counts_after,
        seeded=reset_result.seeded,
    )
    if options.delete_files:
        root = Path(__file__).resolve().parents[3]
        file_cleanup = delete_managed_files(
            [
                root / "outputs" / "document_archives",
                root / "outputs" / "document_archive_batches",
                root / "backend" / "uploads" / "logistics",
            ]
        )
        result = SystemInitializeResult(
            mode=result.mode,
            database=result.database,
            backup_path=result.backup_path,
            counts_before=result.counts_before,
            counts_after=result.counts_after,
            seeded={**result.seeded, **file_cleanup},
        )
    summary_path = write_summary_report(output, result)
    return SystemInitializeResult(
        mode=result.mode,
        database=result.database,
        backup_path=result.backup_path,
        summary_path=summary_path,
        counts_before=result.counts_before,
        counts_after=result.counts_after,
        seeded=result.seeded,
    )
