"""Caching utilities for Census data."""

from pathlib import Path
import pandas as pd
import hashlib
import json

def get_cache_key(params):
    '''Generate cache key from parameters.'''
    # create deterministic string from params
    param_str = json.dumps(params, sort_keys=True)
    return hashlib.md5(param_str.encode()).hexdigest()[:16]

def get_cache_path(cache_dir, cache_type, params):
    '''
    Get cache file path.

    Parameters
    ----------
    cache_dir : str or Path
        Cache directory
    cache_type : str
        'api' or 'geometries'
    params : dict
        Query parameters for cache key

    Returns
    -------
    Path
        Cache file path
    '''
    cache_dir = Path(cache_dir)
    cache_subdir = cache_dir / cache_type
    cache_subdir.mkdir(parents=True, exist_ok=True)

    # generate filename
    key = get_cache_key(params)
    dataset = params.get('dataset', 'acs5')
    year = params.get('year', 2021)
    geography = params.get('geography', 'tract')
    state = params.get('state', '')
    county = params.get('county', '')

    filename = f"{dataset}_{year}_{geography}_{state}_{county}_{key}"

    if cache_type == 'api':
        return cache_subdir / f"{filename}.csv"
    else:
        return cache_subdir / filename

def save_to_cache(data, cache_path, is_spatial=False):
    '''
    Save data to cache.

    Parameters
    ----------
    data : DataFrame or GeoDataFrame
        Data to cache
    cache_path : Path
        Cache file path
    is_spatial : bool
        If True, save as GeoPackage + Shapefile
    '''
    if is_spatial:
        # save as GeoPackage
        gpkg_path = cache_path.parent / f"{cache_path.stem}.gpkg"
        data.to_file(gpkg_path, driver='GPKG')

        # save as Shapefile
        shp_dir = cache_path
        shp_dir.mkdir(exist_ok=True)
        data.to_file(shp_dir / f"{cache_path.stem}.shp")
    else:
        # save as CSV
        data.to_csv(cache_path, index=False)

def load_from_cache(cache_path, is_spatial=False):
    '''
    Load data from cache.

    Parameters
    ----------
    cache_path : Path
        Cache file path
    is_spatial : bool
        If True, load GeoPackage

    Returns
    -------
    DataFrame or GeoDataFrame or None
        Cached data or None if not found
    '''
    if is_spatial:
        gpkg_path = cache_path.parent / f"{cache_path.stem}.gpkg"
        if gpkg_path.exists():
            import geopandas as gpd
            return gpd.read_file(gpkg_path)
    else:
        if cache_path.exists():
            header = pd.read_csv(cache_path, nrows=0)
            if 'GEOID' in header.columns:
                return pd.read_csv(cache_path, dtype={'GEOID': 'string'})
            return pd.read_csv(cache_path)

    return None
