#!/usr/bin/env python3
"""
generate_hosts_n1_whole_new_zone

讀取 ~/bin/hosts，根據指定的 WS ID 範圍，自動將新的 WS / WHS / WORLDDB / WWEBSPS
附加到對應的 IP 行，或新增 IP 行（若不存在）。

新 Zone 的內容插入在 footer 警告區塊（# DO NOT CHANGE THE SERVER NAMES ABOVE）之前。

用法:
  generate_hosts_n1_whole_new_zone <Region Name> <Zone ID> <MS IP> <WS IP Init> <WS ID Start> <WS ID End>

範例:
  generate_hosts_n1_whole_new_zone "EU (S32)" 32 10.8.73.12 10.8.73.121 3231 3240
  generate_hosts_n1_whole_new_zone "EU (S32)" 32 10.8.73.12 10.8.73.121 3201 3299

對應規則（WS ID 尾數 → IP offset from WS IP Init）:
  尾數 1 → +0, 尾數 2 → +1, ..., 尾數 9 → +8, 尾數 0 → +9
"""

import sys
import re
from pathlib import Path

HOSTS_FILE    = Path.home() / "bin" / "hosts"
FOOTER_MARKER = "DO NOT CHANGE THE SERVER NAMES ABOVE"


def usage():
    print(
        f"Usage: {sys.argv[0]} "
        '"<Region Name>" <Zone ID> <MS IP> <WS IP Init> <WS ID Start> <WS ID End>'
    )
    sys.exit(1)


def calc_ws_ip(ws_ip_init: str, ws_id: int) -> str:
    """根據 WS ID 尾數算出對應 IP"""
    last_digit = ws_id % 10
    offset = (last_digit - 1 + 10) % 10
    prefix, last_octet = ws_ip_init.rsplit(".", 1)
    return f"{prefix}.{int(last_octet) + offset}"


def build_aliases(zone_id: int, ws_id: int) -> str:
    """產生單個 WS 的 5 個別名（WS / WHS×2 / WORLDDB / WWEBSPS）"""
    wid = ws_id - zone_id * 100
    w = f"{wid:02d}"
    return (
        f"WS{zone_id}{w} "
        f"WHS{zone_id}{w}1 "
        f"WHS{zone_id}{w}2 "
        f"WORLDDB{zone_id}{w} "
        f"WWEBSPS{zone_id}{w}1"
    )


def ip_key(ip: str) -> tuple:
    return tuple(int(x) for x in ip.split("."))


def find_footer_idx(lines: list[str]) -> int:
    """找到 footer 警告區塊起始行的 index，找不到回傳 len(lines)"""
    for i, line in enumerate(lines):
        if FOOTER_MARKER in line:
            # 往回找到該區塊的第一行（##### 那行）
            for j in range(i - 1, -1, -1):
                if lines[j].startswith("#####"):
                    return j
            return i
    return len(lines)


def main():
    if len(sys.argv) != 7:
        usage()

    region_name = sys.argv[1]
    zone_id     = int(sys.argv[2])
    ms_ip       = sys.argv[3]
    ws_ip_init  = sys.argv[4]
    ws_id_start = int(sys.argv[5])
    ws_id_end   = int(sys.argv[6])

    # ── 驗證參數 ──────────────────────────────────────────────────────────────
    if ws_id_start > ws_id_end:
        print(f"錯誤：WS ID 起始 ({ws_id_start}) 不能大於結束 ({ws_id_end})")
        sys.exit(1)

    expected_zone = ws_id_start // 100
    if expected_zone != zone_id:
        print(f"警告：WS ID {ws_id_start} 與 Zone ID {zone_id} 不符（預期 Zone {expected_zone}）")

    # ── 計算每個 WS ID 對應的 IP 與別名 ──────────────────────────────────────
    new_by_ip: dict[str, list[str]] = {}
    for ws_id in range(ws_id_start, ws_id_end + 1):
        ip = calc_ws_ip(ws_ip_init, ws_id)
        new_by_ip.setdefault(ip, []).append(build_aliases(zone_id, ws_id))

    # ── 讀取 hosts 檔案 ───────────────────────────────────────────────────────
    if HOSTS_FILE.exists():
        lines = HOSTS_FILE.read_text().splitlines()
    else:
        lines = []

    # ── 檢查是否有重複別名 ────────────────────────────────────────────────────
    all_new_aliases: set[str] = set()
    for aliases_str in sum(new_by_ip.values(), []):
        for alias in aliases_str.split():
            all_new_aliases.add(alias.upper())

    existing_aliases: set[str] = set()
    for line in lines:
        if line.strip().startswith("#"):
            continue
        parts = line.split()
        for alias in parts[1:]:
            existing_aliases.add(alias.upper())

    duplicates = all_new_aliases & existing_aliases
    if duplicates:
        print("錯誤：以下別名已存在於 hosts 檔案中，請確認後再執行：")
        for dup in sorted(duplicates):
            print(f"  {dup}")
        sys.exit(1)

    # ── 檢查 Zone 是否已存在（依 GAMEDB{zone_id} 判斷）────────────────────────
    zone_marker = f"GAMEDB{zone_id}"
    has_zone = any(
        zone_marker in line and not line.strip().startswith("#")
        for line in lines
    )

    result = list(lines)
    footer_idx = find_footer_idx(result)

    # ── 若新 Zone，在 footer 之前插入 comment + MS/GDS 行 ─────────────────────
    if not has_zone:
        new_zone_lines = [
            f"## {region_name}",
            f"{ms_ip} GDS{zone_id} MS{zone_id} GAMEDB{zone_id} SOCIETYS{zone_id} SOCIETYDB{zone_id} RANKS{zone_id} CHATS{zone_id}",
        ]
        for line in reversed(new_zone_lines):
            result.insert(footer_idx, line)
        footer_idx += len(new_zone_lines)

    # ── 處理每個 WS IP 行 ─────────────────────────────────────────────────────
    for ip in sorted(new_by_ip.keys(), key=ip_key):
        additions = " " + " ".join(new_by_ip[ip])

        # 找既有行
        found_idx = None
        for i, line in enumerate(result):
            parts = line.split()
            if parts and parts[0] == ip:
                found_idx = i
                break

        if found_idx is not None:
            # 附加到既有行（單空格）
            result[found_idx] = result[found_idx].rstrip() + additions
        else:
            # 找插入位置：在 Zone 區段內，依 IP 數值順序，不超過 footer
            zone_line_idx = None
            for i, line in enumerate(result):
                if zone_marker in line and not line.strip().startswith("#"):
                    zone_line_idx = i
                    break

            insert_idx = find_footer_idx(result)
            if zone_line_idx is not None:
                for i in range(zone_line_idx + 1, find_footer_idx(result)):
                    line = result[i]
                    if line.startswith("##"):
                        insert_idx = i
                        break
                    parts = line.split()
                    if parts and re.match(r"\d+\.\d+\.\d+\.\d+", parts[0]):
                        if ip_key(parts[0]) > ip_key(ip):
                            insert_idx = i
                            break

            result.insert(insert_idx, f"{ip}{additions}")

    # ── 寫回 hosts 檔案 ───────────────────────────────────────────────────────
    output = "\n".join(result)
    if not output.endswith("\n"):
        output += "\n"
    HOSTS_FILE.write_text(output)

    wid_s = ws_id_start - zone_id * 100
    wid_e = ws_id_end   - zone_id * 100
    print(f"✓ {HOSTS_FILE}  WS{zone_id}{wid_s:02d} ~ WS{zone_id}{wid_e:02d} 已更新")


if __name__ == "__main__":
    main()
