<?php
/**
 * Per-user media folder icon colors (preset ids), stored in user meta as JSON.
 *
 * @package FleekDash\Services
 * @since   2.4.4
 */

namespace FleekDash\Services;

use FleekDash\Taxonomies\MediaFolderTaxonomy;

defined('ABSPATH') || exit;

class MediaFolderUserColorsService
{
    public const USER_META_KEY = 'fleekdash_media_folder_colors';

    /** @var list<string> */
    private const VALID_COLOR_IDS = ['amber', 'blue', 'emerald', 'violet', 'rose', 'slate'];

    /**
     * @return array<string, string> Term ID string => color preset id
     */
    public function getMapForUser(int $userId): array
    {
        $map = [];
        if ($userId > 0) {
            $raw = \get_user_meta($userId, self::USER_META_KEY, true);
            if (\is_string($raw) && $raw !== '') {
                $decoded = \json_decode($raw, true);
                if (\is_array($decoded)) {
                    $map = $this->sanitizeColorMap($decoded);
                }
            }
        }

        return $map;
    }

    /**
     * @return array<string, string>
     */
    public function getMapForCurrentUser(): array
    {
        $uid = (int) \get_current_user_id();

        return $this->getMapForUser($uid);
    }

    /**
     * @param array<mixed, mixed> $input
     * @return array<string, string>
     */
    private function sanitizeColorMap(array $input): array
    {
        $out = [];
        foreach ($input as $key => $value) {
            $termId = \absint($key);
            if ($termId <= 0) {
                continue;
            }
            if ($value === null || $value === '') {
                continue;
            }
            $colorId = \sanitize_key((string) $value);
            if (!\in_array($colorId, self::VALID_COLOR_IDS, true)) {
                continue;
            }
            $out[(string) $termId] = $colorId;
        }

        return $out;
    }

    /**
     * @return array{ok: bool, message: string, normalized: string|null}
     */
    private function resolveColorPresetForUpdate(?string $colorId): array
    {
        if ($colorId === null || $colorId === '') {
            return ['ok' => true, 'message' => '', 'normalized' => null];
        }
        $candidate = \sanitize_key($colorId);
        if (\in_array($candidate, self::VALID_COLOR_IDS, true)) {
            return ['ok' => true, 'message' => '', 'normalized' => $candidate];
        }

        return ['ok' => false, 'message' => 'Invalid color', 'normalized' => null];
    }

    /**
     * @return array{canSave: bool, message: string, normalizedColor: string|null}
     */
    private function validateSetColorRequest(int $uid, int $termId, ?string $colorId): array
    {
        $message = '';
        $normalizedColor = null;
        $canSave = false;

        if ($uid <= 0) {
            $message = 'Not authenticated';
        } elseif ($termId <= 0) {
            $message = 'Invalid folder';
        } else {
            $term = \get_term($termId, MediaFolderTaxonomy::TAXONOMY);
            if (\is_wp_error($term) || !$term) {
                $message = 'Folder not found';
            } else {
                $resolved = $this->resolveColorPresetForUpdate($colorId);
                if (!$resolved['ok']) {
                    $message = $resolved['message'];
                } else {
                    $canSave = true;
                    $normalizedColor = $resolved['normalized'];
                }
            }
        }

        return [
            'canSave'          => $canSave,
            'message'          => $message,
            'normalizedColor'  => $normalizedColor,
        ];
    }

    /**
     * @return array{success: bool, colors: array<string, string>, message: string}
     */
    private function persistUserFolderColorMap(int $uid, int $termId, ?string $normalizedColor): array
    {
        $result = [
            'success'  => false,
            'colors'   => [],
            'message'  => '',
        ];
        $map = $this->getMapForUser($uid);
        if ($normalizedColor === null) {
            unset($map[(string) $termId]);
        } else {
            $map[(string) $termId] = $normalizedColor;
        }
        $encoded = \wp_json_encode($map, \JSON_UNESCAPED_UNICODE);
        if (!\is_string($encoded)) {
            $result['message'] = 'Failed to encode colors';
        } else {
            \update_user_meta($uid, self::USER_META_KEY, $encoded);
            $result['success'] = true;
            $result['colors'] = $map;
        }

        return $result;
    }

    /**
     * @return array{success: bool, colors: array<string, string>, message: string}
     */
    public function setColorForCurrentUser(int $termId, ?string $colorId): array
    {
        $uid = (int) \get_current_user_id();
        $validation = $this->validateSetColorRequest($uid, $termId, $colorId);
        $result = [
            'success'  => false,
            'colors'   => [],
            'message'  => '',
        ];
        if ($validation['canSave']) {
            $result = $this->persistUserFolderColorMap($uid, $termId, $validation['normalizedColor']);
        }
        if ($validation['message'] !== '') {
            $result['message'] = $validation['message'];
        }

        return $result;
    }

    /**
     * Merge a sanitized map into the current user's stored colors (used for localStorage migration).
     *
     * @param array<string, string> $incoming
     * @return array{success: bool, colors: array<string, string>, merged: int}
     */
    public function mergeMapsForCurrentUser(array $incoming): array
    {
        $out = [
            'success' => false,
            'colors'  => [],
            'merged'  => 0,
        ];
        $uid = (int) \get_current_user_id();
        if ($uid > 0) {
            $existing = $this->getMapForUser($uid);
            $sanitized = $this->sanitizeColorMap($incoming);
            $merged    = 0;
            foreach ($sanitized as $tid => $cid) {
                if (!isset($existing[$tid])) {
                    $existing[$tid] = $cid;
                    $merged++;
                }
            }

            $encodedOk = true;
            if ($merged > 0) {
                $encoded = \wp_json_encode($existing, \JSON_UNESCAPED_UNICODE);
                $encodedOk = \is_string($encoded);
                if ($encodedOk) {
                    \update_user_meta($uid, self::USER_META_KEY, $encoded);
                }
            }

            if ($merged === 0 || $encodedOk) {
                $out['success'] = true;
                $out['colors']  = $existing;
                $out['merged']  = $merged;
            }
        }

        return $out;
    }
}
