from pathlib import Path

from jinja2 import Environment

from pgai.vectorizer.generate.function_parser import (
    PostgresFunction,
    VectorizerParameter,
)

TEMPLATE = '''"""This file is generated by the configuration generator
in generate/config_generator.py. Do not modify by hand."""
from dataclasses import dataclass
from typing import ClassVar, Any, TypeAlias
from datetime import datetime, timedelta

JsonDict: TypeAlias = dict[str, Any]

def format_sql_params(params: dict[str, str | None | bool | list[str]]) -> str:
    """Format dictionary of parameters into SQL argument string without any quoting."""
    formatted: list[str] = []
    for key, value in params.items():
        if value is None:
            continue
        elif isinstance(value, bool):
            formatted.append(f"{key}=>{str(value).lower()}")
        elif isinstance(value, list):
            array_list = ",".join(f"E'{v}'" for v in value)
            formatted.append(f"{key}=>ARRAY[{array_list}]")
        elif isinstance(value, timedelta):
            formatted.append(f"{key}=>'{value.seconds} seconds'")
        else:
            formatted.append(f"{key}=> '{value}'")
    return ", ".join(formatted)

class SQLArgumentMixin:
    arg_type: ClassVar[str]
    function_name: ClassVar[str]

    def to_sql_argument(self) -> str:
        params = {}
        for field_name in self.__dataclass_fields__:  # type: ignore
            if field_name != "arg_type" and field_name != "function_name":
                value = getattr(self, field_name)  # type: ignore
                if value is not None:
                    params[field_name] = value

        return f", {self.arg_type} => {self.function_name}({format_sql_params(params)})"  # type: ignore

{% for function in functions %}


@dataclass
class {{ function.name|replace('ai.', '')|replace('_', ' ')|title|replace(' ', '') }}Config(SQLArgumentMixin):
    """Configuration for {{ function.name }} function."""
    arg_type: ClassVar[str] = "{{ function.name|split('.')|last|split('_')|first }}"
    function_name: ClassVar[str] = "{{ function.name }}"

    {% for param in function.parameters %}
    {{ param.name }}: {{ param.python_type }}{% if param.is_required == False %} = None{% endif %}

    {% endfor %}
{% endfor %}
'''

VECTORIZER_TEMPLATE = '''"""This file is generated by the configuration generator
in generate/config_generator.py. Do not modify by hand."""
from typing import Any
from dataclasses import dataclass

from .configuration import SQLArgumentMixin

# Dynamic imports based on parameter types
from .configuration import (
    {% for function in functions %}    {{ function.name|replace('ai.', '')|replace('_', ' ')|title|replace(' ', '') }}Config{%- if not loop.last %},
    {% endif %}{% endfor %}

)


@dataclass
class CreateVectorizer:
    """Parameters for ai.create_vectorizer function"""
    {% for param in parameters %}
    {{ param.name }}: {{ param.python_type }}{% if not param.is_required %} = None{% endif %}
    
    {% endfor %}

    def to_sql(self) -> str:
        """Convert parameters to SQL function call"""
        parts = ["SELECT ai.create_vectorizer("]

        parts.append(f"'{self.source}'::regclass")

        # Handle all config objects that implement SQLArgumentMixin
        for field_name, field_value in self.__dict__.items():
            if isinstance(field_value, SQLArgumentMixin):
                parts.append(field_value.to_sql_argument())
            elif field_value is not None and field_name not in ('source',):
                # Handle primitive types
                if isinstance(field_value, bool):
                    parts.append(f", {field_name} => {str(field_value).lower()}")
                elif isinstance(field_value, list):
                    values = ",".join(f"'{v}'" for v in field_value)  # type: ignore
                    parts.append(f", {field_name} => ARRAY[{values}]")
                else:
                    parts.append(f", {field_name} => '{field_value}'")

        parts.append(")")
        return "\\n".join(parts)
'''


def generate_vectorizer_params(
    parameters: list[VectorizerParameter],
    output_file: Path,
    functions: list[PostgresFunction],
) -> None:
    """Generate CreateVectorizerParams class from metadata"""
    env = Environment(trim_blocks=True, lstrip_blocks=True)
    template = env.from_string(VECTORIZER_TEMPLATE)

    output = template.render(parameters=parameters, functions=functions)
    output_file.write_text(output)


def generate_config_classes(
    functions: list[PostgresFunction], output_file: Path
) -> None:
    """Generate Python configuration classes from function metadata."""
    env = Environment(trim_blocks=True, lstrip_blocks=True)

    # Add custom filters
    env.filters["split"] = lambda x, sep: x.split(sep)  # type: ignore

    template = env.from_string(TEMPLATE)
    output = template.render(functions=functions)
    output_file.write_text(output)
