<?php

declare(strict_types=1);

namespace App\Services\NovaCards;

use App\Models\NovaCard;
use App\Models\NovaCardTemplate;
use Illuminate\Support\Arr;

class NovaCardProjectNormalizer
{
    public function normalize(?array $project, ?NovaCardTemplate $template = null, array $attributes = [], ?NovaCard $card = null): array
    {
        return $this->upgradeToV3($project, $template, $attributes, $card);
    }

    public function isLegacyProject(?array $project): bool
    {
        return (int) Arr::get($project, 'schema_version', 1) < 3;
    }

    public function upgradeToV3(?array $project, ?NovaCardTemplate $template = null, array $attributes = [], ?NovaCard $card = null): array
    {
        // First normalize to v2 as the base, then layer on v3 additions.
        $v2 = $this->upgradeToV2($project, $template, $attributes, $card);

        // v3: enrich background with v3-specific fields.
        $v3Background = array_merge($v2['background'], [
            'brightness' => (int) Arr::get($project, 'background.brightness', Arr::get($attributes, 'brightness', 0)),
            'contrast' => (int) Arr::get($project, 'background.contrast', Arr::get($attributes, 'contrast', 0)),
            'texture_overlay' => (string) Arr::get($project, 'background.texture_overlay', Arr::get($attributes, 'texture_overlay', '')),
            'gradient_direction' => (string) Arr::get($project, 'background.gradient_direction', Arr::get($attributes, 'gradient_direction', 'to-bottom')),
        ]);

        // v3: enrich typography with v3-specific fields.
        $v3Typography = array_merge($v2['typography'], [
            'quote_mark_preset' => (string) Arr::get($project, 'typography.quote_mark_preset', Arr::get($attributes, 'quote_mark_preset', 'none')),
            'text_panel_style' => (string) Arr::get($project, 'typography.text_panel_style', Arr::get($attributes, 'text_panel_style', 'none')),
            'text_glow' => (bool) Arr::get($project, 'typography.text_glow', Arr::get($attributes, 'text_glow', false)),
            'text_stroke' => (bool) Arr::get($project, 'typography.text_stroke', Arr::get($attributes, 'text_stroke', false)),
        ]);

        // v3: canvas safe zones and layout anchors.
        $v3Canvas = [
            'snap_guides' => (bool) Arr::get($project, 'canvas.snap_guides', true),
            'safe_zones' => (bool) Arr::get($project, 'canvas.safe_zones', true),
        ];

        // v3: frame pack reference.
        $v3Frame = [
            'frame_preset' => (string) Arr::get($project, 'frame.frame_preset', Arr::get($attributes, 'frame_preset', 'none')),
            'frame_color' => (string) Arr::get($project, 'frame.frame_color', Arr::get($attributes, 'frame_color', '')),
        ];

        // v3: effects layer (glow overlays, vignette, etc.)
        $v3Effects = [
            'vignette' => (bool) Arr::get($project, 'effects.vignette', Arr::get($attributes, 'vignette', false)),
            'vignette_strength' => (string) Arr::get($project, 'effects.vignette_strength', 'soft'),
            'color_grade' => (string) Arr::get($project, 'effects.color_grade', Arr::get($attributes, 'color_grade', 'none')),
            'glow_overlay' => (bool) Arr::get($project, 'effects.glow_overlay', Arr::get($attributes, 'glow_overlay', false)),
        ];

        // v3: export preferences (what the creator last chose).
        $v3ExportPrefs = [
            'preferred_format' => (string) Arr::get($project, 'export_preferences.preferred_format', Arr::get($attributes, 'export_preferred_format', 'preview')),
            'include_watermark' => (bool) Arr::get($project, 'export_preferences.include_watermark', true),
        ];

        // v3: source/attribution context.
        $v3SourceContext = [
            'original_card_id' => Arr::get($v2, 'meta.remix.original_card_id'),
            'root_card_id' => Arr::get($v2, 'meta.remix.root_card_id'),
            'original_creator_id' => Arr::get($attributes, 'original_creator_id', $card?->original_creator_id),
            'preset_id' => Arr::get($attributes, 'preset_id', Arr::get($project, 'source_context.preset_id')),
        ];

        return array_merge($v2, [
            'schema_version' => 3,
            'meta' => array_merge($v2['meta'], [
                'editor' => 'nova-cards-v3',
            ]),
            'canvas' => $v3Canvas,
            'background' => $v3Background,
            'typography' => $v3Typography,
            'frame' => $v3Frame,
            'effects' => $v3Effects,
            'export_preferences' => $v3ExportPrefs,
            'source_context' => $v3SourceContext,
        ]);
    }

    public function upgradeToV2(?array $project, ?NovaCardTemplate $template = null, array $attributes = [], ?NovaCard $card = null): array
    {
        $project = is_array($project) ? $project : [];
        $templateConfig = is_array($template?->config_json) ? $template->config_json : [];
        $existingContent = is_array(Arr::get($project, 'content')) ? Arr::get($project, 'content') : [];

        $title = trim((string) Arr::get($attributes, 'title', Arr::get($existingContent, 'title', $card?->title ?? 'Untitled card')));
        $quoteText = trim((string) Arr::get($attributes, 'quote_text', Arr::get($existingContent, 'quote_text', $card?->quote_text ?? 'Your next quote starts here.')));
        $quoteAuthor = trim((string) Arr::get($attributes, 'quote_author', Arr::get($existingContent, 'quote_author', $card?->quote_author ?? '')));
        $quoteSource = trim((string) Arr::get($attributes, 'quote_source', Arr::get($existingContent, 'quote_source', $card?->quote_source ?? '')));
        $textBlocks = $this->normalizeTextBlocks(Arr::wrap(Arr::get($project, 'text_blocks', [])), [
            'title' => $title,
            'quote_text' => $quoteText,
            'quote_author' => $quoteAuthor,
            'quote_source' => $quoteSource,
        ]);

        [$syncedTitle, $syncedQuote, $syncedAuthor, $syncedSource] = $this->syncLegacyContent($textBlocks, [
            'title' => $title,
            'quote_text' => $quoteText,
            'quote_author' => $quoteAuthor,
            'quote_source' => $quoteSource,
        ]);

        if (array_key_exists('title', $attributes)) {
            $syncedTitle = $title;
        }

        if (array_key_exists('quote_text', $attributes)) {
            $syncedQuote = $quoteText;
        }

        if (array_key_exists('quote_author', $attributes)) {
            $syncedAuthor = $quoteAuthor;
        }

        if (array_key_exists('quote_source', $attributes)) {
            $syncedSource = $quoteSource;
        }

        $gradientKey = (string) Arr::get($project, 'background.gradient_preset', Arr::get($attributes, 'gradient_preset', Arr::get($templateConfig, 'gradient_preset', 'midnight-nova')));
        $fontKey = (string) Arr::get($project, 'typography.font_preset', Arr::get($attributes, 'font_preset', Arr::get($templateConfig, 'font_preset', 'modern-sans')));
        $sourceLineEnabled = collect($textBlocks)->contains(fn (array $block): bool => ($block['type'] ?? null) === 'source' && (bool) ($block['enabled'] ?? true) && trim((string) ($block['text'] ?? '')) !== '');
        $authorLineEnabled = collect($textBlocks)->contains(fn (array $block): bool => ($block['type'] ?? null) === 'author' && (bool) ($block['enabled'] ?? true) && trim((string) ($block['text'] ?? '')) !== '');

        return [
            'schema_version' => 2,
            'template' => [
                'id' => $template?->id ?? Arr::get($project, 'template.id'),
                'slug' => $template?->slug ?? Arr::get($project, 'template.slug'),
            ],
            'meta' => [
                'editor' => 'nova-cards-v2',
                'remix' => [
                    'original_card_id' => Arr::get($attributes, 'original_card_id', $card?->original_card_id),
                    'root_card_id' => Arr::get($attributes, 'root_card_id', $card?->root_card_id),
                ],
            ],
            'content' => [
                'title' => $syncedTitle,
                'quote_text' => $syncedQuote,
                'quote_author' => $syncedAuthor,
                'quote_source' => $syncedSource,
            ],
            'text_blocks' => $textBlocks,
            'layout' => [
                'layout' => (string) Arr::get($project, 'layout.layout', Arr::get($attributes, 'layout', Arr::get($templateConfig, 'layout', 'quote_heavy'))),
                'position' => (string) Arr::get($project, 'layout.position', Arr::get($attributes, 'position', 'center')),
                'alignment' => (string) Arr::get($project, 'layout.alignment', Arr::get($attributes, 'alignment', Arr::get($templateConfig, 'text_align', 'center'))),
                'padding' => (string) Arr::get($project, 'layout.padding', Arr::get($attributes, 'padding', 'comfortable')),
                'max_width' => (string) Arr::get($project, 'layout.max_width', Arr::get($attributes, 'max_width', 'balanced')),
            ],
            'typography' => [
                'font_preset' => $fontKey,
                'text_color' => (string) Arr::get($project, 'typography.text_color', Arr::get($attributes, 'text_color', Arr::get($templateConfig, 'text_color', '#ffffff'))),
                'accent_color' => (string) Arr::get($project, 'typography.accent_color', Arr::get($attributes, 'accent_color', '#e0f2fe')),
                'quote_size' => (int) Arr::get($project, 'typography.quote_size', Arr::get($attributes, 'quote_size', 72)),
                'author_size' => (int) Arr::get($project, 'typography.author_size', Arr::get($attributes, 'author_size', 28)),
                'letter_spacing' => (int) Arr::get($project, 'typography.letter_spacing', Arr::get($attributes, 'letter_spacing', 0)),
                'line_height' => (float) Arr::get($project, 'typography.line_height', Arr::get($attributes, 'line_height', 1.2)),
                'shadow_preset' => (string) Arr::get($project, 'typography.shadow_preset', Arr::get($attributes, 'shadow_preset', 'soft')),
                'author_line_enabled' => $authorLineEnabled,
                'source_line_enabled' => $sourceLineEnabled,
            ],
            'background' => [
                'type' => (string) Arr::get($project, 'background.type', Arr::get($attributes, 'background_type', $card?->background_type ?? 'gradient')),
                'gradient_preset' => $gradientKey,
                'gradient_colors' => array_values(Arr::wrap(Arr::get($project, 'background.gradient_colors', Arr::get($attributes, 'gradient_colors', Arr::get(config('nova_cards.gradient_presets'), $gradientKey . '.colors', ['#0f172a', '#1d4ed8']))))),
                'solid_color' => (string) Arr::get($project, 'background.solid_color', Arr::get($attributes, 'solid_color', '#111827')),
                'background_image_id' => Arr::get($attributes, 'background_image_id', Arr::get($project, 'background.background_image_id', $card?->background_image_id)),
                'overlay_style' => (string) Arr::get($project, 'background.overlay_style', Arr::get($attributes, 'overlay_style', Arr::get($templateConfig, 'overlay_style', 'dark-soft'))),
                'focal_position' => (string) Arr::get($project, 'background.focal_position', Arr::get($attributes, 'focal_position', 'center')),
                'blur_level' => (int) Arr::get($project, 'background.blur_level', Arr::get($attributes, 'blur_level', 0)),
                'opacity' => (int) Arr::get($project, 'background.opacity', Arr::get($attributes, 'opacity', 50)),
            ],
            'decorations' => array_values(Arr::wrap(Arr::get($project, 'decorations', Arr::get($attributes, 'decorations', [])))),
            'assets' => [
                'pack_ids' => array_values(array_filter(
                    array_map('intval', Arr::wrap(Arr::get($project, 'assets.pack_ids', Arr::get($attributes, 'asset_pack_ids', []))))
                )),
                'template_pack_ids' => array_values(array_filter(
                    array_map('intval', Arr::wrap(Arr::get($project, 'assets.template_pack_ids', Arr::get($attributes, 'template_pack_ids', []))))
                )),
                'items' => array_values(Arr::wrap(Arr::get($project, 'assets.items', []))),
            ],
        ];
    }

    public function normalizeForCard(NovaCard $card): array
    {
        return $this->normalize($card->project_json, $card->template, [
            'title' => $card->title,
            'quote_text' => $card->quote_text,
            'quote_author' => $card->quote_author,
            'quote_source' => $card->quote_source,
            'background_type' => $card->background_type,
            'background_image_id' => $card->background_image_id,
            'original_card_id' => $card->original_card_id,
            'root_card_id' => $card->root_card_id,
        ], $card);
    }

    public function syncTopLevelAttributes(array $project): array
    {
        [$title, $quoteText, $quoteAuthor, $quoteSource] = $this->syncLegacyContent(Arr::wrap(Arr::get($project, 'text_blocks', [])), Arr::get($project, 'content', []));

        return [
            'schema_version' => (int) Arr::get($project, 'schema_version', 3),
            'title' => $title,
            'quote_text' => $quoteText,
            'quote_author' => $quoteAuthor !== '' ? $quoteAuthor : null,
            'quote_source' => $quoteSource !== '' ? $quoteSource : null,
            'background_type' => (string) Arr::get($project, 'background.type', 'gradient'),
            'background_image_id' => Arr::get($project, 'background.background_image_id'),
        ];
    }

    private function normalizeTextBlocks(array $blocks, array $fallback): array
    {
        $normalized = collect($blocks)
            ->map(function ($block, int $index): array {
                $block = is_array($block) ? $block : [];

                return [
                    'key' => (string) Arr::get($block, 'key', 'block-' . ($index + 1)),
                    'type' => (string) Arr::get($block, 'type', 'body'),
                    'text' => (string) Arr::get($block, 'text', ''),
                    'enabled' => ! array_key_exists('enabled', $block) || (bool) Arr::get($block, 'enabled', true),
                    'style' => is_array(Arr::get($block, 'style')) ? Arr::get($block, 'style') : [],
                ];
            })
            ->filter(fn (array $block): bool => $block['type'] !== '' && $block['key'] !== '')
            ->values();

        if ($normalized->isEmpty()) {
            $normalized = collect([
                ['key' => 'title', 'type' => 'title', 'text' => (string) ($fallback['title'] ?? ''), 'enabled' => true, 'style' => ['role' => 'eyebrow']],
                ['key' => 'quote', 'type' => 'quote', 'text' => (string) ($fallback['quote_text'] ?? ''), 'enabled' => true, 'style' => ['role' => 'headline']],
                ['key' => 'author', 'type' => 'author', 'text' => (string) ($fallback['quote_author'] ?? ''), 'enabled' => (string) ($fallback['quote_author'] ?? '') !== '', 'style' => ['role' => 'byline']],
                ['key' => 'source', 'type' => 'source', 'text' => (string) ($fallback['quote_source'] ?? ''), 'enabled' => (string) ($fallback['quote_source'] ?? '') !== '', 'style' => ['role' => 'caption']],
            ]);
        }

        return $normalized->take((int) config('nova_cards.validation.max_text_blocks', 8))->values()->all();
    }

    private function syncLegacyContent(array $blocks, array $fallback): array
    {
        $title = trim((string) ($fallback['title'] ?? 'Untitled card'));
        $quoteText = trim((string) ($fallback['quote_text'] ?? 'Your next quote starts here.'));
        $quoteAuthor = trim((string) ($fallback['quote_author'] ?? ''));
        $quoteSource = trim((string) ($fallback['quote_source'] ?? ''));

        foreach ($blocks as $block) {
            if (! is_array($block) || ! ($block['enabled'] ?? true)) {
                continue;
            }

            $text = trim((string) ($block['text'] ?? ''));
            if ($text === '') {
                continue;
            }

            $type = (string) ($block['type'] ?? '');
            if ($type === 'title') {
                $title = $text;
            } elseif ($type === 'quote') {
                $quoteText = $text;
            } elseif ($type === 'author') {
                $quoteAuthor = $text;
            } elseif ($type === 'source') {
                $quoteSource = $text;
            }
        }

        return [$title !== '' ? $title : 'Untitled card', $quoteText !== '' ? $quoteText : 'Your next quote starts here.', $quoteAuthor, $quoteSource];
    }
}