"""Metadata access and caching for Census variables."""

from pathlib import Path
import sqlite3
import requests
from pycen.datasets import normalize_dataset

_MEM_CACHE = {}

def _get_cache_settings():
    '''Get metadata cache settings from pycen config.'''
    try:
        import pycen
        return pycen.get_metadata_cache_settings()
    except Exception:
        return (False, None)

def _fetch_variables_from_api(year, dataset):
    '''Fetch variable metadata from Census API.'''
    dataset_path = normalize_dataset(dataset)
    url = f"https://api.census.gov/data/{year}/{dataset_path}/variables.json"
    try:
        response = requests.get(url)
    except requests.exceptions.RequestException as exc:
        raise ValueError(
            f"Network error while fetching metadata for {year} {dataset}: {exc}"
        ) from exc
    if response.status_code == 404:
        raise ValueError(
            f"Dataset/year unavailable: {year} {dataset}."
        )
    if response.status_code != 200:
        raise ValueError(
            f"Census API error while fetching metadata for {year} {dataset}: "
            f"HTTP {response.status_code}."
        )
    data = response.json()
    variables = data.get('variables')
    if not isinstance(variables, dict):
        raise ValueError(
            f"Dataset/year unavailable: {year} {dataset}."
        )
    return variables

def _ensure_tables(conn):
    '''
    Create a table to cache Census variable metadata locally 
    to avoid having to fetch from the API every time.
    '''
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS variables (
            code TEXT PRIMARY KEY,
            label TEXT,
            concept TEXT,
            predicate_type TEXT,
            group_code TEXT,
            year INTEGER,
            dataset TEXT
        )
    ''')
    conn.commit()

def _load_from_db(db_path, year, dataset):
    '''Load cached variable metadata from local database.'''
    if not db_path.exists():
        return None
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute('''
        SELECT code, label, concept, predicate_type, group_code
        FROM variables
        WHERE year = ? AND dataset = ?
        ORDER BY code
    ''', (year, dataset))
    rows = cursor.fetchall()
    conn.close()
    if not rows:
        return None
    variables = {}
    for code, label, concept, predicate_type, group_code in rows:
        variables[code] = {
            'label': label,
            'concept': concept,
            'predicateType': predicate_type,
            'group': group_code
        }
    return variables

def _save_to_db(db_path, year, dataset, variables):
    '''Save variable metadata to local database cache.'''
    db_path.parent.mkdir(parents=True, exist_ok=True)
    conn = sqlite3.connect(db_path)
    _ensure_tables(conn)
    cursor = conn.cursor()
    rows = []
    for code, info in variables.items():
        if not code.endswith('E') or code in ['for', 'in', 'ucgid']:
            continue
        rows.append((
            code,
            info.get('label'),
            info.get('concept'),
            info.get('predicateType'),
            info.get('group'),
            year,
            dataset
        ))
    cursor.executemany('''
        INSERT OR REPLACE INTO variables
        (code, label, concept, predicate_type, group_code, year, dataset)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    ''', rows)
    conn.commit()
    conn.close()

def get_variables(year, dataset):
    '''
    Get variable metadata for a dataset/year, with caching.

    Returns dict of variable codes to metadata (label, concept, type, group).
    Uses memory cache, then database cache, then fetches from API if needed.
    '''
    cache_key = (dataset, year)
    if cache_key in _MEM_CACHE:
        return _MEM_CACHE[cache_key]

    cache_enabled, cache_path = _get_cache_settings()
    cache_db = Path(cache_path) if cache_enabled and cache_path else None

    if cache_db:
        variables = _load_from_db(cache_db, year, dataset)
        if variables is not None:
            _MEM_CACHE[cache_key] = variables
            return variables

    variables = _fetch_variables_from_api(year, dataset)
    _MEM_CACHE[cache_key] = variables
    if cache_db:
        _save_to_db(cache_db, year, dataset, variables)
    return variables
