"""DSS Archive Exporter - Creates .dss files for project export/import"""

import json
import zipfile
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, Optional, List
from .migrations import MigrationManager
from ..models.project import Project
from ..models.theme import Theme, DesignToken
from ..models.component import Component


class DSSArchiveManifest:
    """Manifest for .dss archive"""

    SCHEMA_VERSION = "1.0.1"

    def __init__(
        self,
        project_name: str,
        project_id: str,
        project_uuid: str,
        export_type: str = "full",
        author: Optional[str] = None,
        description: Optional[str] = None,
    ):
        self.dss_version = "2.5.1"
        self.schema_version = self.SCHEMA_VERSION
        self.export_timestamp = datetime.utcnow().isoformat() + "Z"
        self.project_name = project_name
        self.project_id = project_id
        self.project_uuid = project_uuid
        self.export_type = export_type  # "full" or "partial"
        self.author = author
        self.description = description
        self.contents = {
            "tokens": {"count": 0, "files": []},
            "components": {"count": 0, "files": []},
            "themes": {"count": 0, "files": []},
        }

    def to_dict(self) -> Dict[str, Any]:
        """Serialize manifest to dict"""
        return {
            "dssVersion": self.dss_version,
            "schemaVersion": self.schema_version,
            "exportTimestamp": self.export_timestamp,
            "projectName": self.project_name,
            "projectId": self.project_id,
            "projectUuid": self.project_uuid,
            "exportType": self.export_type,
            "author": self.author,
            "description": self.description,
            "contents": self.contents,
        }

    def to_json(self) -> str:
        """Serialize manifest to JSON"""
        return json.dumps(self.to_dict(), indent=2)


class DSSArchiveExporter:
    """Exports DSS projects to .dss archive format"""

    def __init__(self, project: Project):
        self.project = project
        self.manifest = DSSArchiveManifest(
            project_name=project.name,
            project_id=project.id,
            project_uuid=project.uuid,
            author=project.metadata.author,
            description=project.description,
        )

    def export_to_file(self, output_path: Path) -> Path:
        """
        Export project to .dss file

        Args:
            output_path: Path where to save the .dss archive

        Returns:
            Path to created archive
        """
        output_path = Path(output_path)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as archive:
            # Write manifest
            archive.writestr("manifest.json", self.manifest.to_json())

            # Export tokens (from theme)
            tokens_data = self._export_tokens()
            if tokens_data:
                archive.writestr("tokens.json", json.dumps(tokens_data, indent=2))
                self.manifest.contents["tokens"]["files"].append("tokens.json")

            # Export themes
            themes_data = self._export_themes()
            if themes_data:
                archive.writestr("themes.json", json.dumps(themes_data, indent=2))
                self.manifest.contents["themes"]["files"].append("themes.json")

            # Export components
            components_data = self._export_components()
            if components_data:
                archive.writestr("components.json", json.dumps(components_data, indent=2))
                self.manifest.contents["components"]["files"].append("components.json")

            # Export config
            config_data = self._export_config()
            if config_data:
                archive.writestr("config.json", json.dumps(config_data, indent=2))

            # Update manifest with final counts and rewrite it
            self.manifest.contents["tokens"]["count"] = len(self._export_tokens().get("tokens", {}))
            self.manifest.contents["components"]["count"] = len(
                self._export_components().get("components", [])
            )
            self.manifest.contents["themes"]["count"] = 1 if themes_data else 0

            archive.writestr("manifest.json", self.manifest.to_json())

        return output_path

    def _export_tokens(self) -> Dict[str, Any]:
        """Export tokens from theme"""
        if not self.project.theme or not self.project.theme.tokens:
            return {}

        tokens_dict = {}
        for token_name, token in self.project.theme.tokens.items():
            tokens_dict[token_name] = self._serialize_token(token)

        return {"tokens": tokens_dict}

    def _export_themes(self) -> Dict[str, Any]:
        """Export theme definition"""
        if not self.project.theme:
            return {}

        return {
            "themes": [
                {
                    "uuid": self.project.theme.uuid,
                    "name": self.project.theme.name,
                    "version": self.project.theme.version,
                    "created_at": self.project.theme.created_at.isoformat(),
                    "updated_at": self.project.theme.updated_at.isoformat(),
                    "tokenRefs": list(self.project.theme.tokens.keys()),
                }
            ]
        }

    def _export_components(self) -> Dict[str, Any]:
        """Export all components"""
        if not self.project.components:
            return {}

        components_list = []
        for component in self.project.components:
            components_list.append(self._serialize_component(component))

        return {"components": components_list}

    def _export_config(self) -> Dict[str, Any]:
        """Export project configuration"""
        return {
            "project": {
                "id": self.project.id,
                "uuid": self.project.uuid,
                "name": self.project.name,
                "version": self.project.version,
                "description": self.project.description,
                "created_at": self.project.metadata.created_at.isoformat(),
                "updated_at": self.project.metadata.updated_at.isoformat(),
                "author": self.project.metadata.author,
                "team": self.project.metadata.team,
                "tags": self.project.metadata.tags,
            }
        }

    def _serialize_token(self, token: DesignToken) -> Dict[str, Any]:
        """Serialize token to export format"""
        return {
            "uuid": token.uuid,
            "$value": token.value,
            "$type": token.type,
            "$category": token.category.value,
            "$description": token.description,
            "$source": token.source,
            "$deprecated": token.deprecated,
            "$createdAt": token.created_at.isoformat(),
            "$updatedAt": token.updated_at.isoformat(),
        }

    def _serialize_component(self, component: Component) -> Dict[str, Any]:
        """Serialize component to export format"""
        return {
            "uuid": component.uuid,
            "name": component.name,
            "source": component.source,
            "description": component.description,
            "variants": component.variants,
            "props": component.props,
            "dependencies": component.dependencies,  # Should be UUIDs
        }


class ArchiveWriter:
    """Low-level archive writing utilities"""

    @staticmethod
    def create_archive(output_path: Path, files: Dict[str, str]) -> Path:
        """
        Create a zip archive with given files

        Args:
            output_path: Path for output .dss file
            files: Dict mapping archive paths to file contents

        Returns:
            Path to created archive
        """
        output_path = Path(output_path)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as archive:
            for archive_path, content in files.items():
                archive.writestr(archive_path, content)

        return output_path


# Export
__all__ = ["DSSArchiveExporter", "DSSArchiveManifest", "ArchiveWriter"]
