import base64
import io
import json
import re
import tempfile
import zipfile
from gzip import GzipFile
from pathlib import Path

from mealie.schema.recipe import RecipeNote

from ._migration_base import BaseMigrator
from .utils.migration_alias import MigrationAlias


def paprika_recipes(file: Path):
    """Yields all recipes inside the export file as JSON"""
    with tempfile.TemporaryDirectory() as tmpdir:
        with zipfile.ZipFile(file) as zip_file:
            zip_file.extractall(tmpdir)

        for name in Path(tmpdir).glob("**/[!.]*.paprikarecipe"):
            with open(name, "rb") as fd:
                with GzipFile("r", fileobj=fd) as recipe_json:
                    recipe = json.load(recipe_json)
                    yield recipe


class PaprikaMigrator(BaseMigrator):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.name = "paprika"

        re_num_list = re.compile(r"^\d+\.\s")

        self.key_aliases = [
            MigrationAlias(key="recipeIngredient", alias="ingredients", func=lambda x: x.split("\n") if x else ""),
            MigrationAlias(key="orgURL", alias="source_url", func=None),
            MigrationAlias(key="totalTime", alias="total_time", func=None),
            MigrationAlias(key="prepTime", alias="prep_time", func=None),
            MigrationAlias(key="performTime", alias="cook_time", func=None),
            MigrationAlias(key="recipeYield", alias="servings", func=None),
            MigrationAlias(
                key="tags", alias="categories", func=None
            ),  # Paprika doesn't support tags, and instead puts tags in categories
            MigrationAlias(key="image", alias="image_url", func=None),
            MigrationAlias(key="dateAdded", alias="created", func=lambda x: x[: x.find(" ")]),
            MigrationAlias(
                key="notes",
                alias="notes",
                func=lambda x: [z for z in [RecipeNote(title="", text=x) if x else None] if z],
            ),
            MigrationAlias(
                key="recipeCategory",
                alias="categories",
                func=self.helpers.get_or_set_category,
            ),
            MigrationAlias(
                key="recipeInstructions",
                alias="directions",
                func=lambda x: [{"text": re.sub(re_num_list, "", s)} for s in x.split("\n\n")] if x else [],
            ),
        ]

    def _migrate(self) -> None:
        recipes = [r for r in paprika_recipes(self.archive) if "name" in r]
        recipe_models = [self.clean_recipe_dictionary(r) for r in recipes]
        results = self.import_recipes_to_database(recipe_models)

        for (slug, recipe_id, status), recipe in zip(results, recipes, strict=True):
            if not status:
                continue

            image_data = recipe.get("photo_data")
            if image_data is None:
                self.logger.info(f"Recipe '{recipe['name']}' has no image")
                continue

            try:
                # Images are stored as base64 encoded strings, so we need to decode them before importing.
                image = io.BytesIO(base64.b64decode(image_data))
                with tempfile.NamedTemporaryFile(suffix=".jpeg") as temp_file:
                    temp_file.write(image.read())
                    temp_file.flush()
                    path = Path(temp_file.name)
                    self.import_image(slug, path, recipe_id, extraction_root=path.parent)
            except Exception as e:
                self.logger.error(f"Failed to import image for {slug}: {e}")
