#!/usr/bin/env python3
from __future__ import annotations

import os
import re
import subprocess
from pathlib import Path
from typing import Optional
import logging

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [INFO] root: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# ─────────────────────────────────────────────────────────────
# 저장 위치 결정
def resolve_output_dir() -> Path:
    here = Path(__file__).resolve().parent
    if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
        base = here.parent
    elif here.name.lower() == "scripts":
        base = here.parent
    else:
        base = here.parent

    out = base / "temp" / "staging"
    out.mkdir(parents=True, exist_ok=True)
    return out


# ─────────────────────────────────────────────────────────────
# iDRAC 계정
IDRAC_USER = "root"
IDRAC_PASS = "calvin"


def run(cmd: list[str]) -> str:
    """racadm 명령 실행 (stdout만 반환)"""
    try:
        return subprocess.getoutput(" ".join(cmd))
    except Exception:
        return ""


def parse_single_value(pattern: str, text: str) -> Optional[str]:
    m = re.search(pattern, text, flags=re.IGNORECASE)
    return m.group(1).strip() if m else None


# ─────────────────────────────────────────────────────────────
# hwinventory 블록 기반 Manufacturer 추출 (핵심 수정 부분)
def extract_manufacturers(hwinventory: str, instance_prefix: str) -> list[str]:
    """
    instance_prefix:
      - 'DIMM.'     → 메모리
      - 'Disk.Bay.' → 디스크
    """
    vendors = []

    blocks = re.split(r"\n\s*\n", hwinventory)
    for block in blocks:
        if f"[InstanceID: {instance_prefix}" in block:
            m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE)
            if m:
                vendors.append(m.group(1).strip())

    return vendors


def fetch_idrac_info_one(ip: str, output_dir: Path) -> None:
    getsysinfo = run([
        "racadm", "-r", ip,
        "-u", IDRAC_USER,
        "-p", IDRAC_PASS,
        "getsysinfo"
    ])

    hwinventory = run([
        "racadm", "-r", ip,
        "-u", IDRAC_USER,
        "-p", IDRAC_PASS,
        "hwinventory"
    ])

    # ── Service Tag
    svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo)
    if not svc_tag:
        logging.error(f"[ERROR] SVC Tag 수집 실패: {ip}")
        return

    # ── iDRAC MAC
    idrac_mac = parse_single_value(
        r"MAC Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo
    )

    # ── Integrated NIC
    integrated_1 = parse_single_value(
        r"NIC\.Integrated\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
        getsysinfo
    )
    integrated_2 = parse_single_value(
        r"NIC\.Integrated\.1-2-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
        getsysinfo
    )

    # ── Embedded NIC
    onboard_1 = parse_single_value(
        r"NIC\.Embedded\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
        getsysinfo
    )
    onboard_2 = parse_single_value(
        r"NIC\.Embedded\.2-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
        getsysinfo
    )

    # ─────────────────────────────────────────────
    # Memory / Disk Vendor (수정 완료)
    mem_vendors = sorted(set(extract_manufacturers(hwinventory, "DIMM.")))
    ssd_vendors = sorted(set(extract_manufacturers(hwinventory, "Disk.Bay.")))

    memory = "\n".join(mem_vendors)
    ssd = "\n".join(ssd_vendors)

    # ── 결과 파일 저장
    out_file = output_dir / f"{svc_tag}.txt"
    with out_file.open("w", encoding="utf-8", newline="\n") as f:
        f.write(f"{svc_tag}\n")
        f.write(f"{integrated_1 or ''}\n")
        f.write(f"{integrated_2 or ''}\n")
        f.write(f"{onboard_1 or ''}\n")
        f.write(f"{onboard_2 or ''}\n")
        f.write(f"{idrac_mac or ''}\n")
        f.write(f"{memory}\n")
        f.write(f"{ssd}\n")

    logging.info(f"[OK] {svc_tag} 수집 완료")


def main(ip_file: str) -> None:
    ip_path = Path(ip_file)
    if not ip_path.is_file():
        logging.error(f"[ERROR] IP 파일 없음: {ip_file}")
        return

    output_dir = resolve_output_dir()

    ips = [
        line.strip()
        for line in ip_path.read_text(encoding="utf-8").splitlines()
        if line.strip()
    ]

    if not ips:
        logging.error("[ERROR] IP 목록이 비어 있습니다.")
        return

    for ip in ips:
        try:
            fetch_idrac_info_one(ip, output_dir)
        except Exception as e:
            logging.error(f"[ERROR] {ip} 처리 실패: {e}")

    # 원본 Bash 스크립트 동작 유지
    try:
        ip_path.unlink(missing_ok=True)
    except Exception:
        pass

    logging.info("정보 수집 완료.")


if __name__ == "__main__":
    import sys
    import time

    if len(sys.argv) != 2:
        logging.error("Usage: python script.py <ip_file>")
        sys.exit(1)

    start = time.time()
    main(sys.argv[1])
    elapsed = int(time.time() - start)

    h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
    logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.")
