"""
Build data-validation model objects from test-runner in-memory data.

Creates ``TableColumnMetadata`` and ``TableConfiguration`` instances that
the data-validation validators (``SchemaDataValidator``,
``MetricsDataValidator``, ``RowDataValidator``) require, populated from
our captured result-set rows and inferred column types rather than from
live ``INFORMATION_SCHEMA`` queries.
"""

from __future__ import annotations

from typing import Any

import pandas as pd

from snowflake.snowflake_data_validation.configuration.model.table_configuration import (
    TableConfiguration,
)
from snowflake.snowflake_data_validation.configuration.model.validation_configuration import (
    ValidationConfiguration,
)
from snowflake.snowflake_data_validation.utils.constants import (
    CALCULATED_COLUMN_SIZE_IN_BYTES_KEY,
    CHARACTER_LENGTH_KEY,
    COLUMN_NAME_KEY,
    DATA_TYPE_KEY,
    DATABASE_NAME_KEY,
    IS_DATA_TYPE_SUPPORTED_KEY,
    IS_PRIMARY_KEY_KEY,
    NULLABLE_KEY,
    PRECISION_KEY,
    ROW_COUNT_KEY,
    SCALE_KEY,
    SCHEMA_NAME_KEY,
    TABLE_NAME_KEY,
)
from snowflake.snowflake_data_validation.utils.model.table_column_metadata import (
    TableColumnMetadata,
)


# ---------------------------------------------------------------------------
# TableColumnMetadata helper
# ---------------------------------------------------------------------------

def build_table_column_metadata(
    column_types: dict[str, str],
    row_count: int,
    code_unit_name: str = "",
) -> TableColumnMetadata:
    """Build a ``TableColumnMetadata`` from inferred types.

    Constructs the DataFrame that ``TableColumnMetadata.__init__`` expects
    from our in-memory column-type dict.
    """
    parts = code_unit_name.replace(".", "_").split("_", 2)
    db_name = parts[0] if len(parts) > 0 else ""
    schema_name = parts[1] if len(parts) > 1 else ""
    table_name = parts[2] if len(parts) > 2 else code_unit_name

    records: list[dict[str, Any]] = []
    for col_name, data_type in column_types.items():
        upper_type = data_type.upper()
        if upper_type.startswith("VARCHAR") or upper_type in ("TEXT", "STRING"):
            char_length = 16000
            calc_size = 16000
        else:
            char_length = float("nan")
            calc_size = 0
        records.append({
            DATABASE_NAME_KEY: db_name,
            SCHEMA_NAME_KEY: schema_name,
            TABLE_NAME_KEY: table_name,
            COLUMN_NAME_KEY: col_name,
            DATA_TYPE_KEY: data_type,
            NULLABLE_KEY: True,
            IS_PRIMARY_KEY_KEY: False,
            CALCULATED_COLUMN_SIZE_IN_BYTES_KEY: calc_size,
            CHARACTER_LENGTH_KEY: char_length,
            PRECISION_KEY: float("nan"),
            SCALE_KEY: float("nan"),
            ROW_COUNT_KEY: row_count,
            IS_DATA_TYPE_SUPPORTED_KEY: True,
        })

    if not records:
        df = pd.DataFrame()
    else:
        df = pd.DataFrame(records)

    return TableColumnMetadata(
        table_column_metadata_df=df,
        column_selection_list=list(column_types.keys()),
    )


# ---------------------------------------------------------------------------
# TableConfiguration helper
# ---------------------------------------------------------------------------

def build_table_configuration(
    code_unit_name: str,
    schema_validation: bool = True,
    metrics_validation: bool = True,
    row_validation: bool = True,
    source_table: str | None = None,
    target_table: str | None = None,
    database: str | None = None,
    schema: str = "VALIDATION",
    index_column_list: list[str] | None = None,
    max_failed_rows_number: int = 100,
    column_selection_list: list[str] | None = None,
) -> TableConfiguration:
    """Build a minimal ``TableConfiguration`` for a stored-procedure baseline.

    Args:
        code_unit_name: The procedure name (used as default if tables not provided).
        schema_validation: Enable schema validation.
        metrics_validation: Enable metrics validation.
        row_validation: Enable row validation.
        source_table: Fully qualified source table name (e.g., DB.SCHEMA.TABLE).
        target_table: Fully qualified target table name (e.g., DB.SCHEMA.TABLE).
        database: Database name (project name from --project-root).
        schema: Schema name (defaults to VALIDATION).
        index_column_list: List of column names to use as index for row validation.
        max_failed_rows_number: Maximum failed rows before stopping row validation.
        column_selection_list: Explicit list of column names to validate.
    """
    source_fqn = source_table or code_unit_name
    target_fqn = target_table or code_unit_name

    target_name = target_fqn.split(".")[-1]

    return TableConfiguration(
        fully_qualified_name=source_fqn,
        use_column_selection_as_exclude_list=False,
        column_selection_list=column_selection_list or [],
        target_name=target_name,
        target_database=database,
        target_schema=schema,
        index_column_list=index_column_list or [],
        chunk_number=10,
        max_failed_rows_number=max_failed_rows_number,
        validation_configuration=ValidationConfiguration(
            schema_validation=schema_validation,
            metrics_validation=metrics_validation,
            row_validation=row_validation,
        ),
    )
