"""
통합 레퍼런스 데이터 관리자
SQLite 로컬 캐시 + Supabase 동기화 준비
"""

import os
import sqlite3
from typing import Dict, Optional, List
from dataclasses import dataclass
from enum import Enum
from pathlib import Path

from app.core.reference_data_defaults import (
    DEFAULT_STATIONS,
    DEFAULT_ERROR_CODES,
    REFERENCE_DATA_VERSION
)


class DoorDirection(Enum):
    DW = "DW"  # Door West (Left)
    DE = "DE"  # Door East (Right)


@dataclass
class StationMeta:
    code: int
    name: str
    pos: float
    door_dir: DoorDirection
    station_no: int
    track_line: str  # 'TC1' or 'TC2'


class ReferenceDataManager:
    """
    통합 레퍼런스 데이터 관리자
    - SQLite 로컬 캐싱
    - 메모리 캐시로 빠른 조회
    - Supabase 동기화 준비
    """
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(ReferenceDataManager, cls).__new__(cls)
            cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if self._initialized:
            return
        
        self._initialized = True
        
        # DB 경로 설정
        self.db_path = Path(__file__).parent / "ref_cache.db"
        
        # 메모리 캐시
        self.tc1_stations: Dict[int, StationMeta] = {}
        self.tc2_stations: Dict[int, StationMeta] = {}
        self.station_name_map: Dict[str, int] = {}
        self.error_code_map: Dict[str, str] = {}
        
        self._is_loaded = False
        
        # 초기화
        self._init_db()
        self._load_to_memory()

    def _init_db(self):
        """DB 초기화 (첫 실행 시 기본 데이터로 생성)"""
        db_exists = self.db_path.exists()
        
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 테이블 생성
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS stations (
                code INTEGER PRIMARY KEY,
                name TEXT NOT NULL,
                pos REAL NOT NULL,
                door_dir TEXT NOT NULL,
                station_no INTEGER NOT NULL,
                track_line TEXT NOT NULL,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS metadata (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS error_codes (
                code TEXT PRIMARY KEY,
                description TEXT NOT NULL
            )
        """)
        
        # 인덱스 생성
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_station_name ON stations(name)")
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_track_line ON stations(track_line)")
        
        # 첫 실행 시 기본 데이터 삽입
        if not db_exists:
            print("[RefData] Initializing database with default data...")
            
            # 역 정보 삽입
            for station in DEFAULT_STATIONS:
                cursor.execute("""
                    INSERT INTO stations (code, name, pos, door_dir, station_no, track_line)
                    VALUES (?, ?, ?, ?, ?, ?)
                """, (
                    station["code"],
                    station["name"],
                    station["pos"],
                    station["door_dir"],
                    station["station_no"],
                    station["track_line"]
                ))
            
            # 에러 코드 삽입
            for code, desc in DEFAULT_ERROR_CODES.items():
                cursor.execute("""
                    INSERT INTO error_codes (code, description)
                    VALUES (?, ?)
                """, (code, desc))
            
            # 버전 정보 삽입
            cursor.execute("""
                INSERT INTO metadata (key, value)
                VALUES ('version', ?)
            """, (REFERENCE_DATA_VERSION,))
            
            conn.commit()
            print(f"[RefData] Database initialized with version {REFERENCE_DATA_VERSION}")
        
        conn.close()

    def _load_to_memory(self):
        """SQLite에서 메모리로 로드 (빠른 조회를 위한 캐싱)"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 역 정보 로드
        cursor.execute("SELECT code, name, pos, door_dir, station_no, track_line FROM stations")
        rows = cursor.fetchall()
        
        for row in rows:
            code, name, pos, door_dir, station_no, track_line = row
            
            station = StationMeta(
                code=code,
                name=name,
                pos=pos,
                door_dir=DoorDirection(door_dir),
                station_no=station_no,
                track_line=track_line
            )
            
            if track_line == "TC1":
                self.tc1_stations[code] = station
            elif track_line == "TC2":
                self.tc2_stations[code] = station
            
            # 이름 매핑 (TC1 우선)
            if track_line == "TC1":
                self.station_name_map[name] = code
        
        # TC2 이름 매핑 (TC1에 없는 경우만)
        for code, station in self.tc2_stations.items():
            if station.name not in self.station_name_map:
                self.station_name_map[station.name] = code
        
        # 에러 코드 로드
        cursor.execute("SELECT code, description FROM error_codes")
        for code, desc in cursor.fetchall():
            self.error_code_map[code] = desc
        
        conn.close()
        
        self._is_loaded = True
        print(f"[RefData] Loaded from cache. TC1: {len(self.tc1_stations)}, TC2: {len(self.tc2_stations)}")

    # ========== 조회 메서드 (기존 API 호환) ==========
    
    def get_station_name(self, code: int) -> str:
        """역 코드로 역 이름 조회"""
        if code in self.tc1_stations:
            return self.tc1_stations[code].name
        if code in self.tc2_stations:
            return self.tc2_stations[code].name
        return ""

    def get_station_info(self, code: int) -> Optional[StationMeta]:
        """역 코드로 역 정보 조회"""
        if code in self.tc1_stations:
            return self.tc1_stations[code]
        if code in self.tc2_stations:
            return self.tc2_stations[code]
        return None

    def get_station_code(self, name: str) -> int:
        """역 이름으로 역 코드 조회"""
        return self.station_name_map.get(name, 0)
    
    def get_station_distance(self, station_name: str, is_tc1: bool) -> float:
        """역 이름으로 거리 조회"""
        target_list = self.tc1_stations if is_tc1 else self.tc2_stations
        for station in target_list.values():
            if station.name == station_name:
                return station.pos
        return 0.0
    
    def get_door_direction(self, station_name_or_code, is_tc1: bool) -> DoorDirection:
        """역 이름 또는 코드로 도어 방향 조회"""
        target_list = self.tc1_stations if is_tc1 else self.tc2_stations
        
        for station in target_list.values():
            if isinstance(station_name_or_code, str):
                if station.name == station_name_or_code:
                    return station.door_dir
            else:
                if station.code == station_name_or_code:
                    return station.door_dir
        
        return DoorDirection.DW

    # ========== Supabase 동기화 (추후 구현) ==========
    
    async def sync_from_supabase(self):
        """
        Supabase에서 최신 데이터 동기화
        TODO: 추후 구현
        """
        pass
    
    def get_version(self) -> str:
        """현재 데이터 버전 조회"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT value FROM metadata WHERE key = 'version'")
        result = cursor.fetchone()
        conn.close()
        return result[0] if result else "unknown"


# 전역 인스턴스
ref_data = ReferenceDataManager()
