"""Runtime geography catalog loading."""

import json
from html.parser import HTMLParser
from pathlib import Path

import requests

from pycen.datasets import DATASET_MAP, normalize_dataset


def _dataset_key(dataset):
    'Resolve dataset key for static catalog names.'
    if dataset in DATASET_MAP:
        return dataset
    for key, value in DATASET_MAP.items():
        if dataset == value:
            return key
    return None


def _cache_path(cache_dir, dataset_key, year):
    'Return cache path for a dataset/year geography catalog.'
    cache_dir = Path(cache_dir) / 'geographies'
    cache_dir.mkdir(parents=True, exist_ok=True)
    return cache_dir / f"{dataset_key}_{year}.json"


def _static_path(dataset_key, year):
    'Return static catalog path if available.'
    data_dir = Path(__file__).parent.parent / 'data'
    return data_dir / f"census_geos_{dataset_key}_{year}.json"


def _parse_geography_html(html_text):
    'Extract geography hierarchy values from geography.html.'
    class _TableParser(HTMLParser):
        'Collect table rows from HTML.'
        def __init__(self):
            super().__init__()
            self.in_table = False
            self.in_row = False
            self.in_cell = False
            self.buf = []
            self.row = []
            self.table = []
            self.tables = []

        def handle_starttag(self, tag, attrs):
            if tag == 'table':
                self.in_table = True
                self.table = []
            if self.in_table and tag == 'tr':
                self.in_row = True
                self.row = []
            if self.in_table and tag in ('th', 'td'):
                self.in_cell = True
                self.buf = []

        def handle_endtag(self, tag):
            if self.in_cell and tag in ('th', 'td'):
                text = ' '.join(''.join(self.buf).split())
                self.row.append(text)
                self.in_cell = False
                self.buf = []
            if self.in_row and tag == 'tr':
                if self.row:
                    self.table.append(self.row)
                self.in_row = False
                self.row = []
            if tag == 'table' and self.in_table:
                if self.table:
                    self.tables.append(self.table)
                self.in_table = False
                self.table = []

        def handle_data(self, data):
            if self.in_cell:
                self.buf.append(data)

    parser = _TableParser()
    parser.feed(html_text)
    geos = []
    for table in parser.tables:
        if not table:
            continue
        headers = [cell.lower() for cell in table[0]]
        if 'geography hierarchy' not in headers:
            continue
        geo_idx = headers.index('geography hierarchy')
        for row in table[1:]:
            if len(row) <= geo_idx:
                continue
            value = row[geo_idx].strip()
            if not value or value.endswith(' items'):
                continue
            value = value.replace('›', ' > ')
            geos.append(' '.join(value.split()))

    return sorted(set(geos))


def load_geography_catalog(dataset, year, cache_dir='./pycen_cache', use_live=True):
    'Load geography catalog using live fetch, cache, then static fallback.'
    dataset_path = normalize_dataset(dataset)
    dataset_key = _dataset_key(dataset)
    if dataset_key is None:
        raise ValueError(f"Unsupported dataset '{dataset}' for static catalogs.")

    if use_live:
        try:
            url = f"https://api.census.gov/data/{year}/{dataset_path}/geography.html"
            response = requests.get(url, timeout=30)
            response.raise_for_status()
            geos = _parse_geography_html(response.text)
            if geos:
                cache_path = _cache_path(cache_dir, dataset_key, year)
                cache_path.write_text(
                    json.dumps({
                        'dataset': dataset_key,
                        'year': year,
                        'source': url,
                        'geographies': geos,
                    }, indent=2),
                    encoding='utf-8'
                )
                return geos, 'live'
        except requests.RequestException:
            pass

    cache_path = _cache_path(cache_dir, dataset_key, year)
    if cache_path.exists():
        data = json.loads(cache_path.read_text(encoding='utf-8'))
        geos = data.get('geographies', [])
        if geos:
            return geos, 'cache'

    static_path = _static_path(dataset_key, year)
    if static_path.exists():
        data = json.loads(static_path.read_text(encoding='utf-8'))
        geos = data.get('geographies', [])
        if geos:
            return geos, 'static'

    raise ValueError(f"No geography catalog available for {dataset_key} {year}.")
