from __future__ import annotations

from collections.abc import Iterable
from dataclasses import dataclass

from sqlalchemy import MetaData

from govoplan_core.core.registry import PlatformRegistry


@dataclass(frozen=True, slots=True)
class MigrationMetadataPlan:
    metadata: tuple[MetaData, ...]
    script_locations: tuple[str, ...]
    modules: tuple[ModuleMigrationMetadata, ...] = ()


@dataclass(frozen=True, slots=True)
class ModuleMigrationMetadata:
    module_id: str
    script_location: str | None = None
    has_metadata: bool = False
    migration_after: tuple[str, ...] = ()
    migration_before: tuple[str, ...] = ()
    migration_tasks: tuple[ModuleMigrationTaskMetadata, ...] = ()


@dataclass(frozen=True, slots=True)
class ModuleMigrationTaskMetadata:
    task_id: str
    phase: str
    summary: str
    task_version: str = "1"
    safety: str = "automatic"
    idempotent: bool = True
    timeout_seconds: int | None = None
    has_executor: bool = False


def migration_metadata_plan(registry: PlatformRegistry, *, extra_metadata: Iterable[MetaData] = ()) -> MigrationMetadataPlan:
    metadata: list[MetaData] = []
    script_locations: list[str] = []
    for item in extra_metadata:
        if item not in metadata:
            metadata.append(item)
    for manifest in registry.manifests():
        spec = manifest.migration_spec
        if spec is None:
            continue
        if isinstance(spec.metadata, MetaData) and spec.metadata not in metadata:
            metadata.append(spec.metadata)
        if spec.script_location:
            script_locations.append(spec.script_location)
    modules = tuple(
        ModuleMigrationMetadata(
            module_id=manifest.id,
            script_location=manifest.migration_spec.script_location,
            has_metadata=isinstance(manifest.migration_spec.metadata, MetaData),
            migration_after=tuple(manifest.migration_spec.migration_after),
            migration_before=tuple(manifest.migration_spec.migration_before),
            migration_tasks=tuple(
                ModuleMigrationTaskMetadata(
                    task_id=task.task_id,
                    phase=task.phase,
                    summary=task.summary,
                    task_version=task.task_version,
                    safety=task.safety,
                    idempotent=task.idempotent,
                    timeout_seconds=task.timeout_seconds,
                    has_executor=task.executor is not None,
                )
                for task in manifest.migration_spec.migration_tasks
            ),
        )
        for manifest in registry.manifests()
        if manifest.migration_spec is not None
    )
    return MigrationMetadataPlan(metadata=tuple(metadata), script_locations=tuple(script_locations), modules=modules)
