import pandas as pd


class SyntacticValidator:
    def __init__(self, sections: dict[pd.DataFrame], resouce_columns: dict):
        self.sections = sections
        self.resource_columns = resouce_columns

    def validate_semantics(self):
        clean_semantically_validated_sections = {}
        for resource_type, resource_df in self.sections.items():
            clean_semantically_validated_sections[resource_type] = (
                self.clean_and_validate_resource_df_syntax(
                    df=resource_df,
                    field_schema=self.resource_columns[resource_type][
                        "required_columns"
                    ],
                    resource_type=resource_type,
                )
            )
        return clean_semantically_validated_sections

        # errors = self.validator.validate_all(sections)
        # if errors:
        #     raise ValueError("Validation errors:\n" + "\n".join(errors))

    def clean_and_validate_resource_df_syntax(
        self, df: pd.DataFrame, field_schema: dict, resource_type: str
    ):
        df = df.copy()
        """Validate all cells in a resource dataframe"""
        for col_name, col in df.items():
            if col_name == "_excel_row":
                continue

            spec = field_schema[col_name]

            for row, value in col.items():
                val = self.clean_and_validate_cell_syntax(
                    value=value,
                    spec=spec,
                    excel_row=df["_excel_row"].iloc[row],
                    col=col_name,
                    resource_type=resource_type,
                )
                # Coerce to column dtype: StringDtype columns only accept str or NA
                if pd.api.types.is_string_dtype(df[col_name]) and val is not None:
                    val = str(val)
                df.loc[row, col_name] = val
        return df

    def clean_and_validate_cell_syntax(
        self, value, spec: dict, excel_row: int, col: str, resource_type: str
    ):
        """Validate a single cell value against its schema spec"""

        if pd.isna(value):

            if spec["required"]:
                raise ValueError(
                    f"{resource_type}: Row {excel_row}, column '{col}' is required but empty"
                )
            return None

        elif spec["type"] == "string":
            return str(value).strip()

        elif spec["type"] == "int":
            try:
                return int(value)
            except Exception:
                raise ValueError(
                    f"{resource_type}: Row {excel_row}, column '{col}': expected int, got '{value}'"
                )

        elif spec["type"] == "ipv4":
            # Just treat as string - actual IPv4 validation happens in constraint handlers
            return str(value).strip()

        else:
            return value
