# app/web/pages/congress.py
from __future__ import annotations
from datetime import datetime, timezone, timedelta
from typing import Optional, Dict, List
import hashlib

from fastapi import APIRouter, Request, Query
from fastapi.responses import HTMLResponse

from app.web.deps import templates, sb

router = APIRouter()

KST = timezone(timedelta(hours=9))


def _to_kst(dt: Optional[str]) -> Optional[str]:
    if not dt:
        return None
    try:
        d = datetime.fromisoformat(dt.replace("Z", "+00:00"))
        return d.astimezone(KST).strftime("%Y-%m-%d %H:%M")
    except Exception:
        return dt


def _person_key(full_name: Optional[str], room_no: Optional[str]) -> str:
    # 동일 인물 기준: 이름 + 방 호수
    base = f"{(full_name or '').strip()}|{(room_no or '').strip()}"
    return hashlib.sha1(base.encode("utf-8")).hexdigest()


@router.get("/congress/changes", response_class=HTMLResponse)
async def congress_changes(
    request: Request,
    days: int = Query(default=14, ge=1, le=365),
    event: Optional[str] = Query(default=None),       # added/updated/closed
    committee: Optional[str] = Query(default=None),   # 선택형
    party: Optional[str] = Query(default=None),       # 선택형
    limit: int = Query(default=200, ge=10, le=2000),
    page: int = Query(default=1, ge=1),
):
    """
    congress_member_events 뷰에서 가져오되,
    동일 인물 기준(full_name + room_no)으로 묶어 "사람 1명 = 1행"만 노출.
    가장 최신 이벤트를 대표로 사용.
    리스트 컬럼: 일시 / 이름 / 정당 / 이벤트 / 변경 내용 / 상세보기
    """
    # 기간 필터
    since = (datetime.now(timezone.utc) - timedelta(days=days)).isoformat()

    # 선택형 옵션(위원회/정당) 수집: 최근 1년치에서 distinct
    # Supabase에서 완전 distinct는 RPC가 필요하지만, 여기서는 많이 가져와서 파이썬에서 중복 제거
    opt_since = (datetime.now(timezone.utc) - timedelta(days=365)).isoformat()
    committees_res = (
        sb.table("congress_member_events")
        .select("committee_name")
        .gte("valid_from", opt_since)
        .not_.is_("committee_name", "null")
        .order("committee_name", desc=False)
        .limit(5000)
        .execute()
    )
    parties_res = (
        sb.table("congress_member_events")
        .select("party")
        .gte("valid_from", opt_since)
        .not_.is_("party", "null")
        .order("party", desc=False)
        .limit(5000)
        .execute()
    )
    committees = sorted({r["committee_name"] for r in (committees_res.data or []) if r.get("committee_name")})
    parties = sorted({r["party"] for r in (parties_res.data or []) if r.get("party")})

    # 본 데이터 쿼리
    q = sb.table("congress_member_events").select("*").gte("valid_from", since)
    if event:
        q = q.eq("event_type", event)
    if committee:
        q = q.eq("committee_name", committee)
    if party:
        q = q.eq("party", party)
    # 넉넉히 가져와서 인물 단위로 축약
    q = q.order("valid_from", desc=True).limit(5000)

    rows: List[dict] = (q.execute().data) or []

    # 인물 단위로 축약(가장 최신 이벤트 1개 대표)
    grouped: Dict[str, dict] = {}
    for r in rows:
        pkey = _person_key(r.get("full_name"), r.get("room_no"))
        if pkey not in grouped:
            grouped[pkey] = {
                "person_key": pkey,
                "latest_valid_from": r.get("valid_from"),
                "latest_valid_from_kst": _to_kst(r.get("valid_from")),
                "full_name": r.get("full_name"),
                "party": r.get("party"),
                "room_no": r.get("room_no"),
                "event_type": r.get("event_type"),
                "changed_fields": r.get("changed_fields") or [],
            }

    # 페이지네이션 (인물 기준)
    people = list(grouped.values())
    total_people = len(people)
    page_size = limit
    start = (page - 1) * page_size
    end = start + page_size
    page_rows = people[start:end]
    pages = (total_people + page_size - 1) // page_size if total_people else 1
    if page > pages:
        page_rows = []

    return templates.TemplateResponse("congress/changes.html", {
        "request": request,
        "rows": page_rows,
        "days": days,
        "event": event or "",
        "committee": committee or "",
        "party": party or "",
        "limit": limit,
        "page": page,
        "pages": pages,
        "total": total_people,
        "committees": committees,
        "parties": parties,
    })


@router.get("/congress/person/{person_key}", response_class=HTMLResponse)
async def congress_person(request: Request, person_key: str):
    """
    동일 인물(이름 + 방호수)의 전체 히스토리를 모아 보여준다.
    - key 탐색: events 전체에서 person_key = sha1(full_name|room_no)
    - 그 이름/방호수로 hist 전체를 불러오고,
      위원회별로만 이전 버전과 비교(diff)한다.
    """
    # 이름/방호수 역추적 (이벤트 뷰에서 찾음)
    evq = (
        sb.table("congress_member_events")
        .select("full_name,room_no")
        .order("valid_from", desc=True)
        .limit(10000)
        .execute()
        .data
        or []
    )
    full_name, room_no = None, None
    for e in evq:
        if _person_key(e.get("full_name"), e.get("room_no")) == person_key:
            full_name, room_no = e.get("full_name"), e.get("room_no")
            break

    if not full_name:
        # 찾을 수 없는 경우
        return templates.TemplateResponse("congress/person.html", {
            "request": request,
            "person_key": person_key,
            "cur": None,
            "timeline": [],
            "current_committees": [],
            "all_committees": [],
            "not_found": True,
        })

    # 해당 이름+방 번호로 hist 모두 조회(최신 → 과거)
    hist = (
        sb.table("congress_member_hist")
        .select("*")
        .eq("full_name", full_name)
        .eq("room_no", room_no)
        .order("valid_from", desc=True)
        .limit(5000)
        .execute()
        .data
        or []
    )

    for r in hist:
        r["_valid_from_kst"] = _to_kst(r.get("valid_from"))
        r["_valid_to_kst"] = _to_kst(r.get("valid_to"))

    # 위원회별 버킷으로 나눠서 “같은 위원회 안에서만” diff
    by_comm: Dict[str, List[dict]] = {}
    for r in hist:
        by_comm.setdefault(r.get("committee_name") or "-", []).append(r)

    def _changes(a: dict, b: Optional[dict]) -> List[dict]:
        if not b:
            return []
        # committee_name은 membership 키이므로 제외
        fields = [
            "role_name", "party", "district", "phone", "room_no",
            "photo_url", "profile_url", "member_page_url",
            "aide_staff", "aide_secretary", "aide_secretary2", "election_count",
        ]
        return [
            {"field": f, "before": b.get(f), "after": a.get(f)}
            for f in fields
            if a.get(f) != b.get(f)
        ]

    timeline: List[dict] = []
    for comm, rows in by_comm.items():
        # rows는 desc 정렬 상태. 같은 위원회 내에서만 이전과 비교
        for i, cur in enumerate(rows):
            prev = rows[i + 1] if i + 1 < len(rows) else None
            timeline.append({"cur": cur, "diff": _changes(cur, prev)})

    # 보기 좋게 전체 타임라인은 시각 역순으로 정렬
    timeline.sort(key=lambda x: x["cur"].get("valid_from") or "", reverse=True)

    # 동일 시점(같은 valid_from)·동일 정보 변경이 위원회별로 중복될 수 있으므로 압축
    compact: Dict[str, dict] = {}
    for it in timeline:
        ts = it["cur"].get("valid_from") or ""
        diffs = it.get("diff") or []
        if not diffs:
            continue
        bucket = compact.setdefault(ts, {"ts": ts, "diff": {}})
        for d in diffs:
            f = d.get("field")
            if not f:
                continue
            prev = bucket["diff"].get(f)
            if prev is None:
                bucket["diff"][f] = {"field": f, "before": d.get("before"), "after": d.get("after")}
            else:
                # 동일 필드가 여러 위원회에서 중복되면 after가 동일한지 확인하고 최신값 유지
                after = d.get("after")
                if after is not None:
                    bucket["diff"][f]["after"] = after

    # compact 리스트로 변환 후 시간 역순 정렬
    timeline_compact: List[dict] = []
    for ts, b in compact.items():
        items = list(b["diff"].values())
        timeline_compact.append({
            "cur": {"valid_from": ts, "_valid_from_kst": _to_kst(ts)},
            "diff": items,
        })
    timeline_compact.sort(key=lambda x: x["cur"].get("valid_from") or "", reverse=True)

    # 현재/전체 위원회
    current_committees = sorted(
        {r["committee_name"] for r in hist if r.get("is_current") and r.get("valid_to") is None and r.get("committee_name")}
    )
    all_committees = sorted({r["committee_name"] for r in hist if r.get("committee_name")})

    # 위원회별 소속 기간 요약 (가장 이른 시작 ~ 가장 늦은 종료)
    # 단, is_current=True 이력이 하나라도 있으면 종료는 '현재'로 표시(= None)
    periods: Dict[str, dict] = {}
    for r in hist:
        cname = r.get("committee_name")
        if not cname:
            continue
        vf = r.get("valid_from") or ""
        vt = r.get("valid_to")  # 일부 파이프라인에서 현재도 배치 시간으로 채워질 수 있음
        is_cur = bool(r.get("is_current"))
        p = periods.setdefault(cname, {"start": None, "end": None, "current": False})
        # start: earliest
        if p["start"] is None or (vf and vf < p["start"]):
            p["start"] = vf
        # mark current if any record says so
        if is_cur or vt is None:
            p["current"] = True
        # track latest non-null end for non-current summary
        if vt is not None:
            if p["end"] is None:
                # keep None only if current already determined; else set vt
                if not p["current"]:
                    p["end"] = vt
            else:
                if vt > p["end"]:
                    p["end"] = vt

    committee_periods = []
    for name, pe in periods.items():
        end_val = None if pe.get("current") else pe.get("end")
        committee_periods.append({
            "name": name,
            "start_kst": _to_kst(pe.get("start")) if pe.get("start") else "-",
            "end_kst": _to_kst(end_val) if end_val else None,
        })
    committee_periods.sort(key=lambda x: x["start_kst"] or "")

    cur = hist[0] if hist else None
    any_changes = any((it.get("diff") for it in timeline_compact))

    return templates.TemplateResponse("congress/person.html", {
        "request": request,
        "person_key": person_key,
        "cur": cur,
        "timeline": timeline_compact,
        "current_committees": current_committees,
        "all_committees": all_committees,
        "committee_periods": committee_periods,
        "any_changes": any_changes,
        "not_found": False,
    })
