import argparse
import json
import os
import sys
import time
import urllib.error
import urllib.request
import http.cookiejar
from pathlib import Path


BASE_URL = "https://downtown.tomohemar.com"
ROOT = Path(__file__).resolve().parents[1]
REFERENCE_DIR = ROOT / "storage" / "reference-extract"


def read_doctor_ids() -> list[str]:
    data = json.loads((REFERENCE_DIR / "doctors.json").read_text(encoding="utf-8"))
    ids: list[str] = []
    for row in data.get("rows", []):
        doctor_id = str(row[0] if row else "").strip()
        if doctor_id:
            ids.append(doctor_id)
    return ids


def make_opener() -> urllib.request.OpenerDirector:
    cookie_jar = http.cookiejar.CookieJar()
    return urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie_jar))


def post_json(opener: urllib.request.OpenerDirector, path: str, payload: dict, timeout: int = 45) -> dict:
    body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    req = urllib.request.Request(
        BASE_URL + path,
        data=body,
        headers={
            "Content-Type": "application/json; charset=utf-8",
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "X-Requested-With": "XMLHttpRequest",
            "User-Agent": "Mozilla/5.0",
        },
    )
    try:
        with opener.open(req, timeout=timeout) as response:
            text = response.read().decode("utf-8-sig")
    except urllib.error.HTTPError as exc:
        text = exc.read().decode("utf-8-sig", "replace")
        raise RuntimeError(f"HTTP {exc.code} from {path}: {text[:700]}") from exc
    return json.loads(text)


def login(opener: urllib.request.OpenerDirector, username: str, password: str) -> None:
    data = post_json(opener, "/Auth/AuthWs.asmx/Login", {"userName": username, "userPassword": password})
    result = data.get("d", {})
    if int(result.get("res", 0) or 0) != 1:
        raise RuntimeError(f"Reference login failed: {result.get('msg') or data}")


def main() -> int:
    parser = argparse.ArgumentParser(description="Read doctor details and specialty mapping from the reference clinic system.")
    parser.add_argument("--username", default=os.getenv("REF_USER", ""), help="Reference system username")
    parser.add_argument("--password", default=os.getenv("REF_PASS", ""), help="Reference system password")
    parser.add_argument("--sleep", type=float, default=0.08, help="Delay between doctor endpoint calls")
    parser.add_argument("--output", default=str(REFERENCE_DIR / "doctor-specialties-live.json"))
    args = parser.parse_args()

    if not args.username or not args.password:
        raise SystemExit("Set REF_USER and REF_PASS or pass --username/--password.")

    REFERENCE_DIR.mkdir(parents=True, exist_ok=True)
    doctor_ids = read_doctor_ids()
    opener = make_opener()
    login(opener, args.username, args.password)

    config_specialists = post_json(opener, "/hc/hcws/hcws.asmx/GetAllConfigSpecialists", {}).get("d", [])
    records: list[dict] = []
    failures: list[dict] = []

    for index, doctor_id in enumerate(doctor_ids, start=1):
        try:
            details = post_json(opener, "/hc/hcws/hcws.asmx/GetDoctorById", {"doctorId": doctor_id}).get("d")
            specialists = post_json(opener, "/hc/hcws/hcws.asmx/GetDoctorSpecialists", {"doctorId": doctor_id}).get("d", [])
            records.append(
                {
                    "doctor_id": doctor_id,
                    "details": details,
                    "specialists": specialists,
                }
            )
            print(f"{index}/{len(doctor_ids)} doctor {doctor_id} ok")
        except Exception as exc:  # Keep the rest of the extraction moving.
            failures.append({"doctor_id": doctor_id, "error": str(exc)})
            print(f"{index}/{len(doctor_ids)} doctor {doctor_id} failed: {exc}", file=sys.stderr)
        time.sleep(max(0.0, args.sleep))

    output = {
        "source": BASE_URL,
        "doctors_count": len(records),
        "failures_count": len(failures),
        "config_specialists": config_specialists,
        "records": records,
        "failures": failures,
    }
    Path(args.output).write_text(json.dumps(output, ensure_ascii=False, indent=2), encoding="utf-8")
    print(f"Wrote {args.output}")
    if failures:
        print(json.dumps(failures, ensure_ascii=False, indent=2), file=sys.stderr)
        return 2
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
