#!/usr/bin/env python3
"""
Parser for https://internship.cse.hcmut.edu.vn/

Extracts: company name, location, maximum slot, acceptance, D2/D3 forms.

Usage:
    python parser.py                    # Print all companies as table
    python parser.py --json out.json    # Export to JSON
    python parser.py --csv out.csv      # Export to CSV
    python parser.py --search "Viettel" # Filter by name
"""

import argparse
import csv
import json
import re
import sys
import time

import requests

BASE_URL = "https://internship.cse.hcmut.edu.vn"
LIST_ENDPOINT = "/home/company/all"
DETAIL_ENDPOINT = "/home/company/id/"

REQUEST_TIMEOUT = 30
USER_AGENT = (
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
)


def fetch_company_list(session: requests.Session) -> list[dict]:
    """Fetch all companies from the list endpoint."""
    url = f"{BASE_URL}{LIST_ENDPOINT}"
    params = {"t": int(time.time() * 1000), "condition": ""}
    resp = session.get(url, params=params, timeout=REQUEST_TIMEOUT)
    resp.raise_for_status()
    data = resp.json()
    return data.get("items", [])


def fetch_company_detail(session: requests.Session, company_id: str) -> dict | None:
    """Fetch detailed info for a single company."""
    url = f"{BASE_URL}{DETAIL_ENDPOINT}{company_id}"
    resp = session.get(url, timeout=REQUEST_TIMEOUT)
    resp.raise_for_status()
    data = resp.json()
    if data.get("error"):
        return None
    return data.get("item")


def classify_form(filename: str) -> str:
    """Classify a form file as D2, D3, or other based on filename pattern."""
    # Patterns like: Horus_D2_TTNT_HK253_... or Company_D3_...
    match = re.search(r"_D([23])_", filename, re.IGNORECASE)
    if match:
        return f"D{match.group(1)}"
    if re.search(r"\bD2\b", filename, re.IGNORECASE):
        return "D2"
    if re.search(r"\bD3\b", filename, re.IGNORECASE):
        return "D3"
    return "other"


def parse_company(session: requests.Session, summary: dict) -> dict | None:
    """Parse a single company: fetch detail and extract relevant fields."""
    company_id = summary.get("_id")
    if not company_id:
        return None

    detail = fetch_company_detail(session, company_id)
    if not detail:
        return None

    # Extract D2/D3 forms from internshipFiles
    d2_forms = []
    d3_forms = []
    other_forms = []
    for f in detail.get("internshipFiles", []):
        name = f.get("name", "")
        path = f.get("path", "")
        form_type = classify_form(name)
        entry = {"name": name, "path": f"{BASE_URL}{path}" if path else ""}
        if form_type == "D2":
            d2_forms.append(entry)
        elif form_type == "D3":
            d3_forms.append(entry)
        else:
            other_forms.append(entry)

    # Also check the main internshipFile
    main_file = detail.get("internshipFile", "")
    if main_file:
        main_name = main_file.rsplit("/", 1)[-1]
        form_type = classify_form(main_name)
        entry = {"name": main_name, "path": f"{BASE_URL}{main_file}"}
        if form_type == "D2":
            d2_forms.append(entry)
        elif form_type == "D3":
            d3_forms.append(entry)
        else:
            other_forms.append(entry)

    max_accepted = detail.get("maxAcceptedStudent", 0)
    student_accepted = detail.get("studentAccepted", 0)
    student_register = detail.get("studentRegister", 0)
    accepted_intern = detail.get("acceptedIntern", False)
    active = detail.get("active", False)

    # Acceptance status
    if not active:
        acceptance = "inactive"
    elif not accepted_intern:
        acceptance = "not_accepting"
    elif student_accepted >= max_accepted:
        acceptance = "full"
    else:
        acceptance = "accepting"

    return {
        "id": company_id,
        "shortname": detail.get("shortname", summary.get("shortname", "")),
        "fullname": detail.get("fullname", summary.get("fullname", "")),
        "location": detail.get("address", ""),
        "max_slot": max_accepted,
        "student_registered": student_register,
        "student_accepted": student_accepted,
        "acceptance": acceptance,
        "is_sponsor": detail.get("isSponsor", False),
        "active": active,
        "d2_forms": d2_forms,
        "d3_forms": d3_forms,
        "other_forms": other_forms,
        "contact_emails": detail.get("contactEmails", []),
        "detail_url": f"{BASE_URL}{DETAIL_ENDPOINT}{company_id}",
    }


def parse_all_companies(search: str | None = None) -> list[dict]:
    """Parse all companies, optionally filtered by name."""
    session = requests.Session()
    session.headers.update({"User-Agent": USER_AGENT})

    print("Fetching company list...", file=sys.stderr)
    companies = fetch_company_list(session)
    print(f"Found {len(companies)} companies", file=sys.stderr)

    if search:
        search_lower = search.lower()
        companies = [
            c for c in companies
            if search_lower in c.get("shortname", "").lower()
            or search_lower in c.get("fullname", "").lower()
        ]
        print(f"Filtered to {len(companies)} companies matching '{search}'", file=sys.stderr)

    results = []
    for i, company in enumerate(companies):
        company_id = company.get("_id", "?")
        shortname = company.get("shortname", "?")
        print(f"  [{i+1}/{len(companies)}] {shortname} ({company_id})", file=sys.stderr)

        parsed = parse_company(session, company)
        if parsed:
            results.append(parsed)

    return results


def print_table(companies: list[dict]):
    """Print companies as a formatted table."""
    if not companies:
        print("No companies found.")
        return

    # Header
    header = (
        f"{'Company':<35} {'Location':<40} {'Max':>5} {'Reg':>5} {'Acc':>5} "
        f"{'Status':<15} {'D2':>3} {'D3':>3}"
    )
    print(header)
    print("-" * len(header))

    for c in companies:
        name = c["shortname"][:34]
        location = c["location"][:39] if c["location"] else "N/A"
        max_slot = c["max_slot"]
        reg = c["student_registered"]
        acc = c["student_accepted"]
        status = c["acceptance"]
        d2 = len(c["d2_forms"])
        d3 = len(c["d3_forms"])

        print(
            f"{name:<35} {location:<40} {max_slot:>5} {reg:>5} {acc:>5} "
            f"{status:<15} {d2:>3} {d3:>3}"
        )

    print(f"\nTotal: {len(companies)} companies")


def export_json(companies: list[dict], filepath: str):
    """Export companies to JSON."""
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(companies, f, ensure_ascii=False, indent=2)
    print(f"Exported to {filepath}")


def export_csv(companies: list[dict], filepath: str):
    """Export companies to CSV."""
    fieldnames = [
        "shortname", "fullname", "location", "max_slot",
        "student_registered", "student_accepted", "acceptance",
        "is_sponsor", "active", "d2_forms", "d3_forms",
        "contact_emails", "detail_url",
    ]
    with open(filepath, "w", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
        writer.writeheader()
        for c in companies:
            row = {k: c[k] for k in fieldnames if k in c}
            row["d2_forms"] = "; ".join(
                f["name"] for f in c.get("d2_forms", [])
            )
            row["d3_forms"] = "; ".join(
                f["name"] for f in c.get("d3_forms", [])
            )
            row["contact_emails"] = "; ".join(c.get("contact_emails", []))
            writer.writerow(row)
    print(f"Exported to {filepath}")


def main():
    parser = argparse.ArgumentParser(
        description="Parse internship companies from CSE HCMUT website"
    )
    parser.add_argument(
        "--json", metavar="FILE", help="Export to JSON file"
    )
    parser.add_argument(
        "--csv", metavar="FILE", help="Export to CSV file"
    )
    parser.add_argument(
        "--search", metavar="TERM", help="Filter companies by name"
    )
    args = parser.parse_args()

    companies = parse_all_companies(search=args.search)

    if args.json:
        export_json(companies, args.json)
    elif args.csv:
        export_csv(companies, args.csv)
    else:
        print_table(companies)


if __name__ == "__main__":
    main()
