from typing import List, Union, cast

from forestadmin.agent_toolkit.utils.forest_schema.action_values import ForestValueConverter
from forestadmin.agent_toolkit.utils.forest_schema.generator_field import SchemaFieldGenerator
from forestadmin.agent_toolkit.utils.forest_schema.type import ForestServerAction, ForestServerActionField
from forestadmin.datasource_toolkit.collections import Collection
from forestadmin.datasource_toolkit.datasources import Datasource
from forestadmin.datasource_toolkit.decorators.collections import CustomizedCollection
from forestadmin.datasource_toolkit.interfaces.actions import Action, ActionField, ActionFieldType
from forestadmin.datasource_toolkit.interfaces.fields import Column, PrimitiveType
from forestadmin.datasource_toolkit.utils.schema import SchemaUtils


class SchemaActionGenerator:

    DUMMY_FIELDS = [
        ForestServerActionField(
            field="Loading...",
            type=SchemaFieldGenerator.build_column_type(PrimitiveType.STRING),
            isReadOnly=True,
            defaultValue="Form is loading",
            value=None,
            description="",
            enums=None,
            hook=None,
            isRequired=False,
            reference=None,
            widget=None,
        )
    ]

    @classmethod
    async def build(
        cls, prefix: str, collection: Union[Collection, CustomizedCollection], name: str
    ) -> ForestServerAction:
        schema = collection.schema["actions"][name]
        idx = list(collection.schema["actions"].keys()).index(name)
        slug = name.lower().replace(r"[^a-z0-9-]+", "-")
        return ForestServerAction(
            id=f"{collection.name}-{idx}-{slug}",
            type=schema.scope.value.lower(),
            name=name,
            baseUrl=None,
            endpoint=f"/{prefix}/_actions/{collection.name}/{idx}/{slug}",
            httpMethod="POST",
            redirect=None,
            download=bool(schema.generate_file),
            fields=await cls.build_fields(collection, schema, name),
            hooks={"load": not schema.static_form, "change": ["changeHook"]},
        )

    @classmethod
    async def build_field_schema(
        cls, datasource: Datasource[Collection], field: ActionField
    ) -> ForestServerActionField:
        output: ForestServerActionField = {
            "value": ForestValueConverter.value_to_forest(field, field["value"]),
            "defaultValue": None,
            "description": field["description"],
            "enums": None,
            "field": field["label"],
            "hook": None,
            "isReadOnly": field["is_read_only"] or False,
            "isRequired": field["is_required"] or True,
            "reference": None,
            "type": PrimitiveType.STRING,
            "widget": None,
        }
        if field["type"] == ActionFieldType.COLLECTION:
            collection: Collection = datasource.get_collection(field["collection_name"])  # type: ignore
            pk = SchemaUtils.get_primary_keys(collection.schema)[0]
            pk_schema = cast(Column, collection.get_field(pk))
            output["type"] = SchemaFieldGenerator.build_column_type(pk_schema["column_type"])  # type: ignore
            output["reference"] = f"{collection.name}.{pk}"
        elif field["type"] == ActionFieldType.ENUM_LIST:
            output["type"] = PrimitiveType.ENUM
        elif field["type"] == ActionFieldType.NUMBER_LIST:
            output["type"] = PrimitiveType.NUMBER
        elif field["type"] == ActionFieldType.FILE:
            output["type"] = "File"
        else:
            output["type"] = PrimitiveType(field["type"].value)

        if field["type"] in [ActionFieldType.ENUM, ActionFieldType.ENUM_LIST]:
            output["enums"] = field["enum_values"]
        if not isinstance(output["type"], str):
            output["type"] = SchemaFieldGenerator.build_column_type(output["type"])

        if field["watch_changes"]:
            output["hook"] = "changeHook"

        return ForestServerActionField(**output)

    @classmethod
    async def build_fields(
        cls, collection: Union[Collection, CustomizedCollection], action: Action, name: str
    ) -> List[ForestServerActionField]:
        if not action.static_form:
            return cls.DUMMY_FIELDS
        fields = await collection.get_form(name, None, None)
        new_fields: List[ForestServerActionField] = []
        for field in fields:
            new_fields.append(await cls.build_field_schema(collection.datasource, field))
        return new_fields
