"""
database.py — ชั้นเชื่อมต่อฐานข้อมูล Order

โหมดการทำงานคุมด้วย env `USE_MYSQL`
  * USE_MYSQL=false (ค่าเริ่มต้น) → ใช้ข้อมูลจำลองในหน่วยความจำ ทดสอบได้ทันทีโดยไม่ต้องมี DB
  * USE_MYSQL=true               → ต่อ MySQL/MariaDB ของ XAMPP จริง (โค้ดเตรียมไว้ครบแล้ว)

ฟังก์ชันหลักที่ชั้น API เรียกใช้คือ  query_order_by_plate(plate_number)
คืน dict ของ Order หรือ None เมื่อไม่พบ — ไม่โยน exception ออกไปให้ API พัง
"""
from __future__ import annotations

import logging
import threading
from datetime import datetime
from typing import Dict, List, Optional

from .config import settings

log = logging.getLogger("database")

# =====================================================================
#  1) ข้อมูลจำลอง (Mockup)
#     key = เลขทะเบียนรูปแบบมาตรฐาน 'NN-NNNN'
# =====================================================================
MOCK_ORDERS: Dict[str, dict] = {
    "70-1234": {
        "order_no": "SO-2026-000118",
        "product": "ปูนซีเมนต์ผง (บัลก์)",
        "driver_name": "สมชาย ใจดี",
        "carrier": "ขนส่งรุ่งเรืองทรานสปอร์ต",
        "weight_text": "31.5 / 32.0 ตัน",
        "status": "อนุมัติแล้ว · พร้อมเข้าชั่ง",
        "queue_no": "A-07",
        "dock": "หลุมโหลด 3",
    },
    "71-5566": {
        "order_no": "SO-2026-000121",
        "product": "หินคลุก 3/4 นิ้ว",
        "driver_name": "ประเสริฐ มั่นคง",
        "carrier": "หจก. ศรีสมบูรณ์ขนส่ง",
        "weight_text": "24.0 / 25.0 ตัน",
        "status": "รอเอกสารต้นทาง",
        "queue_no": "B-02",
        "dock": "หลุมโหลด 1",
    },
    "82-9012": {
        "order_no": "SO-2026-000125",
        "product": "น้ำตาลทรายขาว 50 กก.",
        "driver_name": "วิชัย แซ่ลิ้ม",
        "carrier": "บจก. เอเชียโลจิสติกส์",
        "weight_text": "18.2 / 20.0 ตัน",
        "status": "อนุมัติแล้ว · พร้อมเข้าชั่ง",
        "queue_no": "A-11",
        "dock": "หลุมโหลด 5",
    },
    "85-4321": {
        "order_no": "SO-2026-000130",
        "product": "เหล็กเส้นกลม SR24",
        "driver_name": "อนุชา พูลทรัพย์",
        "carrier": "ไทยสตีลทรานสปอร์ต",
        "weight_text": "27.8 / 30.0 ตัน",
        "status": "ยกเลิก · ติดต่อฝ่ายขาย",
        "queue_no": "",
        "dock": "-",
    },
}

# นับจำนวนครั้งที่รถแต่ละคันถูกสแกน + เวลาเข้าครั้งแรกของวัน (จำลอง check-in)
_checkin_log: Dict[str, str] = {}
_lock = threading.Lock()


# =====================================================================
#  2) การเชื่อมต่อ MySQL (เตรียมโค้ดไว้ให้ เปิดใช้ด้วย USE_MYSQL=true)
# =====================================================================
_pool = None


def _get_pool():
    """
    สร้าง Connection Pool ครั้งเดียว (thread-safe)
    ต้องติดตั้ง:  pip install mysql-connector-python
    """
    global _pool
    if _pool is not None:
        return _pool
    with _lock:
        if _pool is not None:
            return _pool
        from mysql.connector import pooling  # import ที่นี่ เพื่อไม่บังคับติดตั้งถ้าใช้ mock
        _pool = pooling.MySQLConnectionPool(
            pool_name="truckq",
            pool_size=5,
            host=settings.DB_HOST,
            port=settings.DB_PORT,
            user=settings.DB_USER,
            password=settings.DB_PASSWORD,
            database=settings.DB_NAME,
            charset="utf8mb4",
            collation="utf8mb4_unicode_ci",
            connection_timeout=5,
            autocommit=True,
        )
        log.info("สร้าง MySQL connection pool สำเร็จ (%s:%s/%s)",
                 settings.DB_HOST, settings.DB_PORT, settings.DB_NAME)
        return _pool


SQL_FIND_ORDER = """
    SELECT  o.order_no,
            o.product_name        AS product,
            o.driver_name,
            o.carrier_name        AS carrier,
            o.net_weight,
            o.quota_weight,
            o.status,
            o.queue_no,
            o.dock_name           AS dock,
            o.checkin_time
    FROM    orders AS o
    WHERE   REPLACE(REPLACE(o.plate_number, '-', ''), ' ', '') = %s
      AND   o.order_date = CURDATE()
      AND   o.is_active = 1
    ORDER BY o.id DESC
    LIMIT   1
"""

SQL_MARK_CHECKIN = """
    UPDATE orders
       SET checkin_time = NOW()
     WHERE order_no = %s
       AND checkin_time IS NULL
"""


def _query_mysql(plate_number: str) -> Optional[dict]:
    """ดึง Order จาก MySQL จริง — คืน None ถ้าไม่พบ, โยน exception ถ้าต่อ DB ไม่ได้"""
    conn = _get_pool().get_connection()
    try:
        cur = conn.cursor(dictionary=True)
        try:
            key = plate_number.replace("-", "").replace(" ", "")
            cur.execute(SQL_FIND_ORDER, (key,))
            row = cur.fetchone()
            if not row:
                return None

            # ประทับเวลาเข้าอัตโนมัติเมื่อสแกนสำเร็จครั้งแรกของวัน
            if not row.get("checkin_time"):
                cur.execute(SQL_MARK_CHECKIN, (row["order_no"],))
                row["checkin_time"] = datetime.now()

            net = row.pop("net_weight", None)
            quota = row.pop("quota_weight", None)
            checkin = row.pop("checkin_time", None)

            return {
                "order_no":    row.get("order_no") or "",
                "product":     row.get("product") or "",
                "driver_name": row.get("driver_name") or "",
                "carrier":     row.get("carrier") or "",
                "weight_text": (f"{float(net):.1f} / {float(quota):.1f} ตัน"
                                if net is not None and quota is not None else "-"),
                "status":      row.get("status") or "",
                "queue_no":    row.get("queue_no") or "",
                "dock":        row.get("dock") or "",
                "checkin_time": (checkin.strftime("%d/%m/%Y %H:%M:%S")
                                 if isinstance(checkin, datetime) else str(checkin or "")),
            }
        finally:
            cur.close()
    finally:
        conn.close()   # คืน connection กลับเข้า pool


# =====================================================================
#  3) ฟังก์ชันหลักที่ API เรียกใช้
# =====================================================================
def query_order_by_plate(plate_number: str) -> Optional[dict]:
    """
    ค้นหา Order จากเลขทะเบียน

    Args:
        plate_number: เลขทะเบียนรูปแบบมาตรฐาน เช่น '70-1234'
    Returns:
        dict ข้อมูล Order พร้อมส่งกลับเป็น JSON ให้ Frontend หรือ None ถ้าไม่พบ

    หมายเหตุ: ฟังก์ชันนี้ "ไม่โยน exception" ออกไป — ถ้าต่อ DB ไม่ได้จะ log
    แล้วถอยไปใช้ข้อมูลจำลอง เพื่อไม่ให้แถวรถหน้าโรงงานหยุดชะงัก
    """
    if not plate_number:
        return None
    key = plate_number.strip()

    # ---- โหมด MySQL ----
    if settings.USE_MYSQL:
        try:
            row = _query_mysql(key)
            if row is not None:
                return row
            log.info("ไม่พบ Order ของทะเบียน %s ใน MySQL", key)
            return None
        except Exception as exc:                       # noqa: BLE001
            # DB ล่ม/เน็ตหลุด → ยังให้ระบบทำงานต่อได้ด้วยข้อมูลจำลอง
            log.error("ต่อ MySQL ไม่ได้ (%s) — ถอยไปใช้ข้อมูลจำลองชั่วคราว", exc)

    # ---- โหมด Mockup ----
    order = MOCK_ORDERS.get(key)
    if not order:
        return None

    result = dict(order)   # copy กัน mutate ข้อมูลต้นฉบับ
    with _lock:
        if key not in _checkin_log:
            _checkin_log[key] = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
        result["checkin_time"] = _checkin_log[key]
    return result


def list_mock_plates() -> List[str]:
    """ใช้ในหน้า /api/health และตอนทดสอบ — บอกว่ามีทะเบียนอะไรให้ลองบ้าง"""
    return sorted(MOCK_ORDERS.keys())


def db_healthcheck() -> dict:
    """ตรวจสถานะฐานข้อมูลสำหรับ endpoint /api/health"""
    if not settings.USE_MYSQL:
        return {"mode": "mock", "ok": True, "plates": list_mock_plates()}
    try:
        conn = _get_pool().get_connection()
        try:
            cur = conn.cursor()
            cur.execute("SELECT 1")
            cur.fetchone()
            cur.close()
        finally:
            conn.close()
        return {"mode": "mysql", "ok": True, "database": settings.DB_NAME}
    except Exception as exc:                           # noqa: BLE001
        return {"mode": "mysql", "ok": False, "error": str(exc)}
