from __future__ import annotations
import os
import argparse
from pathlib import Path
from collections import OrderedDict
import pandas as pd

# ------------------------------------------------------------
# Cross-platform root resolver (Windows / Linux / macOS)
# ------------------------------------------------------------
def resolve_data_root() -> Path:
    """
    Priority:
      1) Env var IDRAC_DATA_DIR (absolute/relative OK)
      2) nearest parent of this file that contains a 'data' folder
      3) ./data under current working directory
    """
    env = os.getenv("IDRAC_DATA_DIR")
    if env:
        return Path(env).expanduser().resolve()

    here = Path(__file__).resolve()
    for p in [here] + list(here.parents):
        if (p / "data").is_dir():
            return (p / "data").resolve()

    return (Path.cwd() / "data").resolve()


DATA_ROOT = resolve_data_root()

# ------------------------------------------------------------
# Utilities
# ------------------------------------------------------------
def read_lines_any_encoding(path: Path) -> list[str]:
    """Read text file trying common encodings (utf-8/utf-8-sig/cp949/euc-kr/latin-1)."""
    encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr", "latin-1"]
    for enc in encodings:
        try:
            with path.open("r", encoding=enc, errors="strict") as f:
                return f.read().splitlines()
        except Exception:
            continue
    # last resort with replacement
    with path.open("r", encoding="utf-8", errors="replace") as f:
        return f.read().splitlines()


def parse_txt_with_st(file_path: Path) -> dict:
    """
    Parse a .txt file:
      - First line becomes 'S/T'
      - Remaining lines in 'Key: Value' form
    Keeps insertion order.
    """
    lines = read_lines_any_encoding(file_path)
    if not lines:
        return {}

    data = OrderedDict()
    data["S/T"] = lines[0].strip()

    for raw in lines[1:]:
        line = raw.strip()
        if not line or ":" not in line:
            continue
        key, value = line.split(":", 1)
        data[key.strip()] = value.strip()

    return dict(data)


def collect_file_list(input_dir: Path, list_file: Path | None) -> list[Path]:
    """
    1) list_file가 주어지고 존재하면: 그 목록 순서대로 <name>.txt를 input_dir에서 찾음
    2) 없으면: input_dir 안의 *.txt 전체를 파일명 오름차순으로 사용
    """
    files: list[Path] = []

    if list_file and list_file.is_file():
        names = [x.strip() for x in read_lines_any_encoding(list_file) if x.strip()]
        for name in names:
            p = input_dir / f"{name}.txt"
            if p.is_file():
                files.append(p)
            else:
                print(f"[WARN] 파일을 찾을 수 없습니다: {p.name}")
        return files

    # fallback: 디렉토리 스캔
    files = sorted(input_dir.glob("*.txt"))
    if not files:
        print(f"[WARN] 입력 폴더에 .txt 파일이 없습니다: {input_dir}")
    return files


def main():
    parser = argparse.ArgumentParser(
        description="GUID/GPU 시리얼 텍스트들을 하나의 Excel로 병합"
    )
    parser.add_argument(
        "--preset",
        choices=["guid", "gpu"],
        default="guid",
        help="경로 프리셋 선택 (guid: 기존 GUID 경로, gpu: gpu_serial 폴더)"
    )
    parser.add_argument(
        "--input-dir",
        type=Path,
        default=None,
        help="입력 텍스트 폴더(기본: preset에 따름)"
    )
    parser.add_argument(
        "--list-file",
        type=Path,
        default=None,
        help="처리할 파일명 목록(txt). 없으면 폴더 내 *.txt 전체 처리"
    )
    parser.add_argument(
        "--output-xlsx",
        type=Path,
        default=None,
        help="출력 엑셀 경로(기본: preset에 따름)"
    )
    args = parser.parse_args()

    # ---- Preset 기본값 설정 ----
    if args.preset == "guid":
        default_input_dir = Path(os.getenv("GUID_TXT_DIR", DATA_ROOT / "repository" / "guid_file"))
        default_list_file = Path(os.getenv("GUID_LIST_FILE", DATA_ROOT / "server_list" / "guid_list.txt"))
        default_output = Path(os.getenv("GUID_OUTPUT_XLSX", DATA_ROOT / "temp" / "staging" / "XE9680_GUID.xlsx"))
    else:  # gpu
        default_input_dir = Path(os.getenv("GPU_TXT_DIR", DATA_ROOT / "repository" / "gpu_serial"))
        default_list_file = Path(os.getenv("GPU_LIST_FILE", DATA_ROOT / "server_list" / "gpu_serial_list.txt"))
        default_output = Path(os.getenv("GPU_OUTPUT_XLSX", DATA_ROOT / "temp" / "staging" / "GPU_SERIALS.xlsx"))

    input_dir: Path = args.input_dir or default_input_dir
    list_file: Path | None = args.list_file or (default_list_file if default_list_file.is_file() else None)
    output_xlsx: Path = args.output_xlsx or default_output

    # 출력 폴더 보장
    output_xlsx.parent.mkdir(parents=True, exist_ok=True)

    if not input_dir.is_dir():
        raise FileNotFoundError(f"입력 폴더가 없습니다: {input_dir}")

    # 파일 목록 수집
    txt_files = collect_file_list(input_dir, list_file)

    # 데이터 누적
    rows: list[dict] = []
    for txt_path in txt_files:
        rows.append(parse_txt_with_st(txt_path))

    if not rows:
        print("[INFO] 병합할 데이터가 없습니다.")
        return

    # DataFrame (모든 키의 합집합 컬럼 생성)
    df = pd.DataFrame(rows)

    # No 열 선두 삽입
    df.insert(0, "No", range(1, len(df) + 1))

    # 저장
    df.to_excel(output_xlsx, index=False)
    print(f"엑셀 파일이 생성되었습니다: {output_xlsx}")


if __name__ == "__main__":
    main()

