"""Functions for creating, modifying, and checking biphysical tables."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_biophysical.ipynb.

# %% auto 0
__all__ = ['make_biophysical_table_template', 'update_bio_db', 'check_biophysical_table']

# %% ../nbs/04_biophysical.ipynb 4
import rasterio
import numpy as np
import pandas as pd
import geopandas as gpd
import yaml
import os

# %% ../nbs/04_biophysical.ipynb 5
from muir import BIOPHYSICAL_DB_COLUMNS
from muir.core import *
from muir.raster import *
from muir.visualization import *

# %% ../nbs/04_biophysical.ipynb 6
def make_biophysical_table_template(
    lulc_df: pd.DataFrame,         # DataFrame with LULC classes and names
    columns: list,                 # List of column names for the biophysical values
    output_csv_path: str           # Output CSV file path
    ) -> pd.DataFrame:
    df = lulc_df.copy().reset_index(drop=True)
    table = pd.DataFrame()
    table["lucode"] = df["class"]
    table["description"] = df["class_name"]
    for col in columns:
        table[col] = ""
    table.to_csv(output_csv_path, index=False)
    return table

# %% ../nbs/04_biophysical.ipynb 11
from pathlib import Path

def update_bio_db(
    biophysical_table_path: str, # Path to biophysical table to change
    lulc_code: int,              # LULC code to update
    param: str|list,                  # Parameter to update
    percentage_change: float,    # Percentage change to apply (e.g., -10 for -10%)
    save_dir:str|None = None      # Wether to save the new biodf to file
):
    bio_df = pd.read_csv(biophysical_table_path)
    change_factor = 1 + (percentage_change / 100)

    if isinstance(param, str):
        param = [param]
    for p in param:
        bio_df.loc[bio_df['lucode'] == lulc_code, p] *= change_factor

    if save_dir:
        Path(save_dir).mkdir(parents=True, exist_ok=True)

        stem = Path(biophysical_table_path).stem
        ext = Path(biophysical_table_path).suffix
        prcnt_str = str(percentage_change).replace('-', 'm') if percentage_change < 0 else "p" + str(percentage_change)
        
        bio_df_name = f"{stem}_lulc{lulc_code}-{''.join(param)}-{prcnt_str}{ext}"
        out_path = Path(save_dir) / bio_df_name

        bio_df.to_csv(out_path, index=False)
        print(f"Modified biophysical table saved to: {out_path}")
    
    return bio_df


# %% ../nbs/04_biophysical.ipynb 20
def check_biophysical_table(
    table: pd.DataFrame,
    model: str = None,
    lulc_df: pd.DataFrame = None
) -> None:
    """
    Checks a biophysical table for common issues and prints results with emojis.
    """
    # 1. Missing values
    missing_cells = table.isnull().sum().sum()
    if missing_cells > 0:
        print(f"❌ Missing values: {int(missing_cells)} cells are empty.")
        for col in table.columns:
            n_missing = table[col].isnull().sum()
            if n_missing > 0:
                print(f"   - Column '{col}': {n_missing} missing")
    else:
        print("✅ No missing values.")

    # 2. Missing columns (if model specified)
    if model:
        required_cols = set(BIOPHYSICAL_DB_COLUMNS.get(model, []))
        missing_cols = required_cols - set(table.columns)
        if missing_cols:
            print(f"❌ Missing required columns for model '{model}': {sorted(missing_cols)}")
        else:
            print(f"✅ All required columns for model '{model}' are present.")

    # 3. Missing lucode column (regardless)
    if 'lucode' not in table.columns:
        print("❌ Missing 'lucode' column.")
    else:
        print("✅ 'lucode' column present.")

    # 4. Missing/extra classes (if lulc_df specified)
    if lulc_df is not None and 'class' in lulc_df.columns and 'lucode' in table.columns:
        expected_classes = set(lulc_df['class'])
        table_classes = set(table['lucode'])
        missing_classes = expected_classes - table_classes
        extra_classes = table_classes - expected_classes

        if missing_classes:
            missing_info = [
                f"{cls} ({lulc_df.loc[lulc_df['class'] == cls, 'class_name'].values[0]})"
                for cls in sorted(missing_classes)
            ]
            print(f"❌ Missing LULC classes in table: {missing_info}")
        else:
            print("✅ All expected LULC classes are present.")

        if extra_classes:
            extra_info = []
            for cls in sorted(extra_classes):
                # Try to get class name from table if available, else just show code
                name = None
                if 'description' in table.columns:
                    name_row = table.loc[table['lucode'] == cls, 'description']
                    if not name_row.empty:
                        name = name_row.values[0]
                extra_info.append(f"{cls} ({name})" if name else str(cls))
            print(f"🟡 Extra LULC classes in table: {extra_info}")
        else:
            print("✅ No extra LULC classes in table.")

    # 5. Duplicate rows
    # Check for duplicated entire rows
    if table.duplicated().any():
        dup_rows = table[table.duplicated()].index.tolist()
        print(f"❌ Duplicate rows at indices: {dup_rows}")
    else:
        print("✅ No duplicate rows.")

    # Check for duplicated lulc class (lucode)
    if 'lucode' in table.columns:
        duplicated_lucode = table['lucode'][table['lucode'].duplicated()].unique()
        if len(duplicated_lucode) > 0:
            print(f"❌ Duplicated 'lucode' values: {duplicated_lucode.tolist()}")
        else:
            print("✅ No duplicated 'lucode' values.")
