<?php

declare(strict_types=1);

/**
 * @deprecated APO-170 keeps this repository as a compatibility read-through for legacy callers.
 * New chrome orchestration work should use MyronFooterDesignRepository.
 */
final class MyronFooterDesignSettingsRepository
{
    private const DEFAULT_VARIANT = 'footer.standard';

    private const VALID_VARIANTS = [
        'footer.standard',
        'footer.portfolio',
        'footer.editorial',
        'footer.mega',
        'footer.ecom',
        'footer.local-business',
        'footer.conversion',
        'footer.creator',
        'footer.campaign',
        'footer.checkout',
    ];

    public function __construct(private readonly PDO $pdo)
    {
    }

    /**
     * @return array<string, mixed>
     */
    public function getSettings(): array
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            $default = myronFooterDesignRepository()->getDefault();
            return [
                'active_variant' => (string) ($default['variant_id'] ?? self::DEFAULT_VARIANT),
                'zone_visibility' => is_array($default['zone_visibility'] ?? null) ? $default['zone_visibility'] : [],
                'updated_by_user_id' => '',
                'created_at' => (string) ($default['created_at'] ?? ''),
                'updated_at' => (string) ($default['updated_at'] ?? ''),
            ];
        }

        $this->ensureDefaultRow();

        $statement = $this->pdo->query('SELECT * FROM footer_design_settings WHERE id = 1 LIMIT 1');
        $row = $statement ? $statement->fetch(PDO::FETCH_ASSOC) : false;

        return $this->normalizeSettings(is_array($row) ? $row : []);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function saveSettings(array $input, string $updatedByUserId): array
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            $settings = $this->normalizeSettings($input, true);
            $repo = myronFooterDesignRepository();
            $repo->saveActivation((string) $settings['active_variant'], true, $updatedByUserId);
            $repo->setDefault((string) $settings['active_variant'], $updatedByUserId);
            $current = $repo->getByVariantId((string) $settings['active_variant']);
            $repo->saveConfiguration(
                (string) $settings['active_variant'],
                is_array($settings['zone_visibility'] ?? null) ? $settings['zone_visibility'] : [],
                is_array($current['zone_content'] ?? null) ? $current['zone_content'] : [],
                $updatedByUserId
            );
            return $this->getSettings();
        }

        $settings = $this->normalizeSettings($input, true);
        $now = myronNow();

        $statement = $this->pdo->prepare(
            'UPDATE footer_design_settings
             SET active_variant = :active_variant,
                 zone_visibility = :zone_visibility,
                 updated_by_user_id = :updated_by_user_id,
                 updated_at = :updated_at
             WHERE id = 1'
        );

        $statement->execute([
            ':active_variant'      => $settings['active_variant'],
            ':zone_visibility'     => json_encode($settings['zone_visibility']),
            ':updated_by_user_id'  => $updatedByUserId,
            ':updated_at'          => $now,
        ]);

        if ($statement->rowCount() === 0) {
            $insert = $this->pdo->prepare(
                'INSERT INTO footer_design_settings
                    (id, active_variant, zone_visibility, updated_by_user_id, created_at, updated_at)
                 VALUES (1, :active_variant, :zone_visibility, :updated_by_user_id, :created_at, :updated_at)'
            );
            $insert->execute([
                ':active_variant'     => $settings['active_variant'],
                ':zone_visibility'    => json_encode($settings['zone_visibility']),
                ':updated_by_user_id' => $updatedByUserId,
                ':created_at'         => $now,
                ':updated_at'         => $now,
            ]);
        }

        return $settings;
    }

    public function recommendedVariantForSiteType(string $bundleId, MyronSiteTypeRegistryRepository $siteTypes): string
    {
        $siteType = $siteTypes->findSiteTypeById($bundleId);
        if (!is_array($siteType)) {
            return self::DEFAULT_VARIANT;
        }

        $variant = trim((string) ($siteType['footerVariant'] ?? ''));
        return in_array($variant, self::VALID_VARIANTS, true) ? $variant : self::DEFAULT_VARIANT;
    }

    public function isUntouchedDefault(): bool
    {
        $settings = $this->getSettings();
        if ((string) ($settings['active_variant'] ?? self::DEFAULT_VARIANT) !== self::DEFAULT_VARIANT) {
            return false;
        }

        return !$this->hasCustomizedZoneContent($this->getAllZoneContent());
    }

    public function seedFromSiteType(string $bundleId, MyronSiteTypeRegistryRepository $siteTypes, string $updatedByUserId): string
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            return myronFooterDesignRepository()->seedFromSiteType($bundleId, $siteTypes, $updatedByUserId);
        }

        $recommended = $this->recommendedVariantForSiteType($bundleId, $siteTypes);
        if ($this->isUntouchedDefault()) {
            $this->saveSettings([
                'active_variant' => $recommended,
                'zone_visibility' => $this->getSettings()['zone_visibility'] ?? [],
            ], $updatedByUserId);
        }

        return $recommended;
    }

    public function applyRecommendation(string $bundleId, string $variant, string $updatedByUserId): void
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            myronFooterDesignRepository()->applyRecommendation($bundleId, $variant, $updatedByUserId);
            return;
        }

        $this->saveSettings([
            'active_variant' => $variant,
            'zone_visibility' => $this->getSettings()['zone_visibility'] ?? [],
        ], $updatedByUserId);
        $this->clearDismissedRecommendation($bundleId, $variant, $updatedByUserId);
    }

    public function dismissRecommendation(string $bundleId, string $variant, string $updatedByUserId): void
    {
        $dismissals = $this->getRecommendationDismissals();
        $dismissals[$this->dismissalKey($bundleId, $variant)] = myronNow();
        $this->saveRecommendationDismissals($dismissals, $updatedByUserId);
    }

    public function isRecommendationDismissed(string $bundleId, string $variant): bool
    {
        $dismissals = $this->getRecommendationDismissals();
        return isset($dismissals[$this->dismissalKey($bundleId, $variant)]);
    }

    /**
     * @return list<string>
     */
    public function validVariants(): array
    {
        return self::VALID_VARIANTS;
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    public function getAllZoneContent(): array
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            $default = myronFooterDesignRepository()->getDefault();
            return is_array($default['zone_content'] ?? null) ? $default['zone_content'] : [];
        }

        $this->ensureDefaultRow();

        $statement = $this->pdo->query('SELECT zone_content_json FROM footer_design_settings WHERE id = 1 LIMIT 1');
        $row = $statement ? $statement->fetch(PDO::FETCH_ASSOC) : false;
        if (!is_array($row)) {
            return [];
        }

        return $this->decodeZoneContentJson((string) ($row['zone_content_json'] ?? ''));
    }

    /**
     * @return array<string, mixed>
     */
    public function getZoneContent(string $zoneId): array
    {
        $all = $this->getAllZoneContent();
        $content = $all[trim($zoneId)] ?? [];
        return is_array($content) ? $content : [];
    }

    /**
     * @param array<string, mixed> $content
     */
    public function saveZoneContent(string $zoneId, array $content, string $updatedByUserId): void
    {
        if ($this->tableExists('footer_designs') && function_exists('myronFooterDesignRepository')) {
            $repo = myronFooterDesignRepository();
            $default = $repo->getDefault();
            $variantId = (string) ($default['variant_id'] ?? self::DEFAULT_VARIANT);
            $all = is_array($default['zone_content'] ?? null) ? $default['zone_content'] : [];
            $all[trim($zoneId)] = $this->normalizeZoneContentValues($content);
            $repo->saveConfiguration(
                $variantId,
                is_array($default['zone_visibility'] ?? null) ? $default['zone_visibility'] : [],
                $all,
                $updatedByUserId
            );
            return;
        }

        $this->ensureDefaultRow();

        $zoneId  = trim($zoneId);
        $all     = $this->getAllZoneContent();
        $all[$zoneId] = $this->normalizeZoneContentValues($content);
        $now     = myronNow();

        $statement = $this->pdo->prepare(
            'UPDATE footer_design_settings
             SET zone_content_json = :zone_content_json,
                 updated_by_user_id = :updated_by_user_id,
                 updated_at = :updated_at
             WHERE id = 1'
        );
        $statement->execute([
            ':zone_content_json'   => json_encode($all, JSON_UNESCAPED_UNICODE),
            ':updated_by_user_id'  => $updatedByUserId,
            ':updated_at'          => $now,
        ]);
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function decodeZoneContentJson(string $raw): array
    {
        if (trim($raw) === '' || trim($raw) === 'null') {
            return [];
        }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return [];
        }
        $result = [];
        foreach ($decoded as $zoneId => $content) {
            if (is_array($content)) {
                $result[trim((string) $zoneId)] = $content;
            }
        }
        return $result;
    }

    /**
     * Strip fully-empty repeater items to avoid blank rows accumulating.
     *
     * @param array<string, mixed> $content
     * @return array<string, mixed>
     */
    private function normalizeZoneContentValues(array $content): array
    {
        $normalized = [];
        foreach ($content as $key => $value) {
            if (is_array($value)) {
                $cleanItems = [];
                $items = array_values(array_filter($value, 'is_array'));
                usort($items, static function (array $a, array $b): int {
                    $aOrder = (int) ($a['__order'] ?? 0);
                    $bOrder = (int) ($b['__order'] ?? 0);
                    return $aOrder <=> $bOrder;
                });

                foreach ($items as $item) {
                    if (!is_array($item)) {
                        continue;
                    }
                    $hasValue = false;
                    foreach ($item as $itemKey => $itemVal) {
                        if (str_starts_with((string) $itemKey, '__')) {
                            continue;
                        }
                        if (trim((string) $itemVal) !== '') {
                            $hasValue = true;
                            break;
                        }
                    }
                    if ($hasValue && empty($item['__remove'])) {
                        unset($item['__order'], $item['__remove']);
                        $cleanItems[] = $item;
                    }
                }
                $normalized[(string) $key] = $cleanItems;
            } else {
                $normalized[(string) $key] = trim((string) $value);
            }
        }
        return $normalized;
    }

    /**
     * @param array<string, array<string, mixed>> $content
     */
    private function hasCustomizedZoneContent(array $content): bool
    {
        foreach ($content as $zoneContent) {
            if ($this->containsNonEmptyValue($zoneContent)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param array<string, mixed> $payload
     */
    private function containsNonEmptyValue(array $payload): bool
    {
        foreach ($payload as $key => $value) {
            if (str_starts_with((string) $key, '__')) {
                continue;
            }
            if (is_array($value)) {
                if ($this->containsNonEmptyValue($value)) {
                    return true;
                }
                continue;
            }
            if (trim((string) $value) !== '') {
                return true;
            }
        }

        return false;
    }

    /**
     * @return array<string, string>
     */
    private function getRecommendationDismissals(): array
    {
        $this->ensureDefaultRow();

        $statement = $this->pdo->query('SELECT footer_recommendation_dismissals_json FROM footer_design_settings WHERE id = 1 LIMIT 1');
        $raw = $statement ? $statement->fetchColumn() : false;
        if (!is_string($raw) || trim($raw) === '') {
            return [];
        }

        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return [];
        }

        $dismissals = [];
        foreach ($decoded as $key => $value) {
            $dismissals[trim((string) $key)] = trim((string) $value);
        }

        return $dismissals;
    }

    /**
     * @param array<string, string> $dismissals
     */
    private function saveRecommendationDismissals(array $dismissals, string $updatedByUserId): void
    {
        $now = myronNow();
        $statement = $this->pdo->prepare(
            'UPDATE footer_design_settings
             SET footer_recommendation_dismissals_json = :dismissals,
                 updated_by_user_id = :updated_by_user_id,
                 updated_at = :updated_at
             WHERE id = 1'
        );
        $statement->execute([
            ':dismissals' => json_encode($dismissals, JSON_UNESCAPED_UNICODE),
            ':updated_by_user_id' => $updatedByUserId,
            ':updated_at' => $now,
        ]);
    }

    public function clearDismissedRecommendation(string $bundleId, string $variant, string $updatedByUserId): void
    {
        $dismissals = $this->getRecommendationDismissals();
        unset($dismissals[$this->dismissalKey($bundleId, $variant)]);
        $this->saveRecommendationDismissals($dismissals, $updatedByUserId);
    }

    private function dismissalKey(string $bundleId, string $variant): string
    {
        return trim($bundleId) . ':' . trim($variant);
    }

    private function ensureDefaultRow(): void
    {
        $count = $this->pdo->query('SELECT COUNT(*) FROM footer_design_settings WHERE id = 1')
            ?->fetchColumn();

        if ((int) $count === 0) {
            $now = myronNow();
            $this->pdo->exec(
                "INSERT INTO footer_design_settings (id, active_variant, zone_visibility, updated_by_user_id, created_at, updated_at)
                 VALUES (1, '" . self::DEFAULT_VARIANT . "', '{}', '', '$now', '$now')"
            );
        }
    }

    private function tableExists(string $table): bool
    {
        $driver = (string) $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
        if ($driver === 'sqlite') {
            $statement = $this->pdo->prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = :table");
            $statement->execute([':table' => $table]);
            return $statement->fetchColumn() !== false;
        }

        $statement = $this->pdo->prepare('SHOW TABLES LIKE :table');
        $statement->execute([':table' => $table]);
        return $statement->fetchColumn() !== false;
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    private function normalizeSettings(array $input, bool $validate = false): array
    {
        $variant = trim((string) ($input['active_variant'] ?? self::DEFAULT_VARIANT));
        if ($variant === '' || !in_array($variant, self::VALID_VARIANTS, true)) {
            if ($validate && $variant !== '') {
                throw new RuntimeException("Unknown footer variant: $variant");
            }
            $variant = self::DEFAULT_VARIANT;
        }

        $rawVisibility = $input['zone_visibility'] ?? [];
        if (is_string($rawVisibility)) {
            $decoded = json_decode($rawVisibility, true);
            $rawVisibility = is_array($decoded) ? $decoded : [];
        }

        $zoneVisibility = [];
        foreach ($rawVisibility as $zoneId => $enabled) {
            $zoneVisibility[trim((string) $zoneId)] = (bool) $enabled;
        }

        return [
            'active_variant'  => $variant,
            'zone_visibility' => $zoneVisibility,
        ];
    }
}
