"""선단 구성 JSX → kcgdb fleet_companies + fleet_vessels 적재.

Usage: python3 prediction/scripts/load_fleet_registry.py
"""

import json
import re
import sys
from pathlib import Path

import psycopg2
import psycopg2.extras

# JSX 파일에서 D 배열 추출
JSX_PATH = Path(__file__).parent.parent.parent.parent / 'gc-wing-dev' / 'legacy' / '선단구성_906척_어업수역 (1).jsx'

# kcgdb 접속 — prediction/.env 또는 환경변수
DB_HOST = '211.208.115.83'
DB_PORT = 5432
DB_NAME = 'kcgdb'
DB_USER = 'kcg_app'
DB_SCHEMA = 'kcg'


def parse_jsx(path: Path) -> list[list]:
    """JSX 파일에서 D=[ ... ] 배열을 파싱."""
    text = path.read_text(encoding='utf-8')

    # const D=[ 부터 ]; 까지 추출
    m = re.search(r'const\s+D\s*=\s*\[', text)
    if not m:
        raise ValueError('D 배열을 찾을 수 없습니다')

    start = m.end() - 1  # [ 위치
    # 중첩 배열을 추적하여 닫는 ] 찾기
    depth = 0
    end = start
    for i in range(start, len(text)):
        if text[i] == '[':
            depth += 1
        elif text[i] == ']':
            depth -= 1
            if depth == 0:
                end = i + 1
                break

    raw = text[start:end]

    # JavaScript → JSON 변환 (trailing comma 제거)
    raw = re.sub(r',\s*]', ']', raw)
    raw = re.sub(r',\s*}', '}', raw)

    return json.loads(raw)


def load_to_db(data: list[list], db_password: str):
    """파싱된 데이터를 DB에 적재."""
    conn = psycopg2.connect(
        host=DB_HOST, port=DB_PORT, dbname=DB_NAME,
        user=DB_USER, password=db_password,
        options=f'-c search_path={DB_SCHEMA}',
    )
    conn.autocommit = False
    cur = conn.cursor()

    try:
        # 기존 데이터 초기화
        cur.execute('DELETE FROM fleet_vessels')
        cur.execute('DELETE FROM fleet_companies')

        company_count = 0
        vessel_count = 0
        pair_links = []  # (vessel_id, pair_vessel_id) 후처리

        for row in data:
            if len(row) < 7:
                continue

            name_cn = row[0]
            name_en = row[1]

            # 회사 INSERT
            cur.execute(
                'INSERT INTO fleet_companies (name_cn, name_en) VALUES (%s, %s) RETURNING id',
                (name_cn, name_en),
            )
            company_id = cur.fetchone()[0]
            company_count += 1

            # 인덱스: 0=own, 1=ownEn, 2=pairs, 3=gn, 4=ot, 5=ps, 6=fc, 7=upt, 8=upts
            pairs = row[2] if len(row) > 2 and isinstance(row[2], list) else []
            gn = row[3] if len(row) > 3 and isinstance(row[3], list) else []
            ot = row[4] if len(row) > 4 and isinstance(row[4], list) else []
            ps = row[5] if len(row) > 5 and isinstance(row[5], list) else []
            fc = row[6] if len(row) > 6 and isinstance(row[6], list) else []
            upt = row[7] if len(row) > 7 and isinstance(row[7], list) else []
            upts = row[8] if len(row) > 8 and isinstance(row[8], list) else []

            def insert_vessel(v, gear_code, role):
                nonlocal vessel_count
                if not isinstance(v, list) or len(v) < 4:
                    return None
                cur.execute(
                    '''INSERT INTO fleet_vessels
                       (company_id, permit_no, name_cn, name_en, tonnage, gear_code, fleet_role)
                       VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING id''',
                    (company_id, v[0], v[1], v[2], v[3], gear_code, role),
                )
                vessel_count += 1
                return cur.fetchone()[0]

            # PT 본선쌍 (pairs)
            for pair in pairs:
                if not isinstance(pair, list) or len(pair) < 2:
                    continue
                main_id = insert_vessel(pair[0], 'C21', 'MAIN')
                sub_id = insert_vessel(pair[1], 'C21', 'SUB')
                if main_id and sub_id:
                    pair_links.append((main_id, sub_id))

            # GN 유자망
            for v in gn:
                insert_vessel(v, 'C25', 'GN')

            # OT 기타
            for v in ot:
                insert_vessel(v, 'C22', 'OT')

            # PS 선망
            for v in ps:
                insert_vessel(v, 'C23', 'PS')

            # FC 운반선
            for v in fc:
                insert_vessel(v, 'C40', 'FC')

            # UPT 단독 본선
            for v in upt:
                insert_vessel(v, 'C21', 'MAIN_SOLO')

            # UPTS 단독 부속선
            for v in upts:
                insert_vessel(v, 'C21', 'SUB_SOLO')

        # PT 쌍 상호 참조 설정
        for main_id, sub_id in pair_links:
            cur.execute('UPDATE fleet_vessels SET pair_vessel_id = %s WHERE id = %s', (sub_id, main_id))
            cur.execute('UPDATE fleet_vessels SET pair_vessel_id = %s WHERE id = %s', (main_id, sub_id))

        conn.commit()
        print(f'적재 완료: {company_count}개 회사, {vessel_count}척 선박, {len(pair_links)}쌍 PT')

    except Exception as e:
        conn.rollback()
        print(f'적재 실패: {e}', file=sys.stderr)
        raise
    finally:
        cur.close()
        conn.close()


if __name__ == '__main__':
    if not JSX_PATH.exists():
        print(f'파일을 찾을 수 없습니다: {JSX_PATH}', file=sys.stderr)
        sys.exit(1)

    # DB 비밀번호 — 환경변수 또는 직접 입력
    import os
    password = os.environ.get('KCGDB_PASSWORD', 'Kcg2026monitor')

    print(f'JSX 파싱: {JSX_PATH}')
    data = parse_jsx(JSX_PATH)
    print(f'파싱 완료: {len(data)}개 회사')

    print('DB 적재 시작...')
    load_to_db(data, password)
