<?php

namespace FluentPlayer\App\Services;

if (!defined('ABSPATH')) exit;

use FluentPlayer\App\Models\Media;
use FluentPlayer\App\Models\Post;
use FluentPlayer\App\Helpers\Helper;
use FluentPlayer\Framework\Support\Arr;

class MediaService
{
    /**
     * Get paginated media items
     *
     * @param array $args Pagination and filtering arguments
     *
     * @return object Paginator instance with media items
     */
    public function paginate($args = [], $with_settings = true)
    {
        // Set default values
        $perPage = max(1, min(100, isset($args['per_page']) ? (int) $args['per_page'] : 10));
        $status = isset($args['status']) ? sanitize_text_field($args['status']) : 'publish';
        $tags = Arr::get($args, 'tags', []);
        $orderByMap = [
            'id'          => 'ID',
            'ID'          => 'ID',
            'title'       => 'post_title',
            'post_title'  => 'post_title',
            'date'        => 'post_date',
            'post_date'   => 'post_date',
            'modified'    => 'post_modified',
            'post_modified' => 'post_modified',
            'post_status' => 'post_status',
            'post_name'   => 'post_name',
        ];
        $orderByArg = isset($args['orderby']) ? sanitize_text_field($args['orderby']) : 'ID';
        $orderBy = isset($orderByMap[$orderByArg]) ? $orderByMap[$orderByArg] : 'ID';
        $order = isset($args['order']) && in_array(strtoupper($args['order']), ['ASC', 'DESC'], true)
            ? strtoupper($args['order'])
            : 'DESC';
        $searchQuery = isset($args['query']) ? sanitize_text_field($args['query']) : '';

        $query = Post::select(['post_title', 'ID', 'post_status', 'post_date', 'post_name'])
            ->where('post_type', Media::$postType)
            ->where('post_status', '!=', 'auto-draft');

        if (is_string($tags)) {
            $tags = explode(',', $tags);
        }

        if (!is_array($tags)) {
            $tags = [];
        }

        $tags = array_values(array_filter(array_map('sanitize_title', $tags)));

        if ($status && $status !== 'all') {
            $query->where('post_status', $status);
        }
        if ($searchQuery) {
            global $wpdb;
            $escapedQuery = $wpdb->esc_like($searchQuery);
            $query->where(function ($q) use ($escapedQuery) {
                $q->where('post_title', 'LIKE', '%' . $escapedQuery . '%')
                    ->orWhere('ID', 'LIKE', '%' . $escapedQuery . '%')
                    ->orWhere('post_status', 'LIKE', '%' . $escapedQuery . '%')
                    ->orWhere('post_name', 'LIKE', '%' . $escapedQuery . '%');
            });
        }

        if (!empty($tags)) {
            if (!taxonomy_exists('flp_media_tag')) {
                $query->where('ID', 0);
            } else {
                $terms = get_terms([
                    'taxonomy'   => 'flp_media_tag',
                    'hide_empty' => false,
                    'slug'       => $tags,
                ]);

                if (is_wp_error($terms) || empty($terms)) {
                    $query->where('ID', 0);
                } else {
                    $termIds = array_map(function ($term) {
                        return (int) $term->term_taxonomy_id;
                    }, $terms);

                    $query->whereExists(function ($subQuery) use ($termIds) {
                        $subQuery->selectRaw('1')
                            ->from('term_relationships')
                            ->whereColumn('term_relationships.object_id', '=', 'posts.ID')
                            ->whereIn('term_relationships.term_taxonomy_id', $termIds);
                    });
                }
            }
        }

        if (!empty($tags)) {
            $args['tags_query_applied'] = true;
        }

        $query = apply_filters('fluent_player/media_paginate_query', $query, $args);

        if ($orderBy && $order) {
            $query->orderBy($orderBy, $order);
            if (in_array($orderBy, ['post_date', 'post_modified', 'post_title'], true)) {
                $query->orderBy('ID', $order);
            }
        } else {
            $query->latest('ID');
        }
        $paginator = $query->paginate($perPage);
        if ($with_settings) {
            $collection = $paginator->getCollection();
            
            // Batch load media settings for all items
            Media::batchLoadMediaSettings($collection->all());

            $allIds = array_map(fn($item) => $item->ID, $collection->all());

            // Tags are a pro feature: pre-populate term cache and fetch per item only when registered
            $tagsEnabled = taxonomy_exists('flp_media_tag');
            if ($tagsEnabled) {
                update_object_term_cache($allIds, 'flp_media_tag');
            }

            $mediasArray = [];
            foreach ($collection as $item) {
                $item->settings = Media::getMediaSettings($item);
                if ($tagsEnabled) {
                    $tags = wp_get_object_terms($item->ID, 'flp_media_tag', ['fields' => 'names']);
                    $item->tags = is_wp_error($tags) ? [] : $tags;
                } else {
                    $item->tags = [];
                }
                $mediasArray[] = $item;
            }
            $paginator->setCollection(new \FluentPlayer\Framework\Support\Collection($mediasArray));
        }
        return $paginator;
    }
    
    /**
     * Prepare complete media data for frontend use
     * Centralized method used by all handlers (shortcode, blocks, AJAX)
     */
    public static function prepareMediaForFrontend($media, $context = 'frontend')
    {
        // Merge preset settings first
        $media->settings = Media::mergePresetSettings($media->settings);

        // Prepare language media sources
        $languageMediaSources = self::prepareLanguageMediaSources($media);

        // Apply iOS Safari settings if needed (after language sources)
        [$isIosSafari, $iosSafariSettings] = self::getIOSSafariSettings();
        if ($isIosSafari) {
            $media->settings = array_merge($media->settings, $iosSafariSettings);
        }

        // Parse smartcodes (e.g. {{contact.first_name}}) via FluentCRM if available
        $media->settings = self::parseSmartcodes($media->settings);

        // Build trusted condition state once and resolve any server-known visibility.
        if (
            Helper::hasPro() &&
            class_exists('\FluentPlayerPro\App\Services\ConditionService')
        ) {
            $media->settings = \FluentPlayerPro\App\Services\ConditionService::maybePrepareConditionState($media->settings, $media->ID);
        }

        $defaultSettings = SettingsService::getMediaDefaultSettings($media->settings);

        // Detect user language for auto-switching
        $serverLang = self::detectUserLanguage();

        return [
            'media'                => $media,
            'default_settings'     => $defaultSettings,
            'languageMediaSources' => $languageMediaSources,
            'serverLang'           => $serverLang,
        ];
    }
    
    /**
     * Prepare language media sources for instant switching
     * Centralized method used by all handlers
     */
    public static function prepareLanguageMediaSources($originalMedia)
    {
        $languageMappings = Arr::get($originalMedia->settings, 'language_mappings', []);
        $languageSources = [];
        
        // Add original media source
        $originalLanguage = Arr::get($originalMedia->settings, 'language', 'en_US');
        $languageSources[$originalLanguage] = [
            'mediaId'   => $originalMedia->ID,
            'src'       => Arr::get($originalMedia->settings, 'src', ''),
            'posterSrc' => Arr::get($originalMedia->settings, 'posterSrc', ''),
            'title'     => $originalMedia->post_title
        ];
        
        // Collect all media IDs first, then batch-load
        $mediaIdToLang = [];
        foreach ($languageMappings as $mapping) {
            $mediaId = Arr::get($mapping, 'media_id');
            $langCode = Arr::get($mapping, 'language');
            if (!empty($mediaId) && !empty($langCode)) {
                $mediaIdToLang[intval($mediaId)] = $langCode;
            }
        }

        if (!empty($mediaIdToLang)) {
            $alternativeMedias = Post::whereIn('ID', array_keys($mediaIdToLang))
                ->where('post_type', Media::$postType)
                ->where('post_status', 'publish')
                ->get();

            Media::batchLoadMediaSettings($alternativeMedias->all());

            foreach ($alternativeMedias as $alternativeMedia) {
                $alternativeMedia->settings = Media::getMediaSettings($alternativeMedia);
                $langCode = $mediaIdToLang[$alternativeMedia->ID] ?? null;
                if ($langCode) {
                    $alternativeMedia->settings = Media::mergePresetSettings($alternativeMedia->settings);
                    $languageSources[$langCode] = [
                        'mediaId'   => $alternativeMedia->ID,
                        'src'       => Arr::get($alternativeMedia->settings, 'src', ''),
                        'posterSrc' => Arr::get($alternativeMedia->settings, 'posterSrc', ''),
                        'title'     => $alternativeMedia->post_title
                    ];
                }
            }
        }
        
        return $languageSources;
    }
    
    /**
     * Detect user language for auto-switching
     */
    public static function detectUserLanguage()
    {
        $serverLang = self::getBrowserLanguage();
        if ($serverLang) {
            return $serverLang;
        }
        return 'en_US';
    }
    
    /**
     * Get browser language from HTTP headers
     * Centralized method used by all handlers
     */
    public static function getBrowserLanguage()
    {
        if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            return null;
        }
        
        $acceptLanguage = sanitize_text_field(wp_unslash($_SERVER['HTTP_ACCEPT_LANGUAGE']));
        $languages = explode(',', $acceptLanguage);
        
        if (empty($languages)) {
            return null;
        }
        
        // Get the first (highest priority) language
        $primaryLanguage = trim(explode(';', $languages[0])[0]);
        
        $wordpressFormat = str_replace('-', '_', $primaryLanguage);
        
        return $wordpressFormat;
    }
    
    /**
     * Get iOS Safari settings for compatibility
     * Centralized method used by all handlers
     */
    public static function getIOSSafariSettings()
    {
        $userAgent = sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'] ?? ''));
        $isIos = preg_match('/iPad|iPhone|iPod/i', $userAgent) && !strpos($userAgent, 'MSStream');
        $isSafari = preg_match('/^((?!chrome|android).)*safari/i', $userAgent);
        $isIosSafari = $isIos || ($isSafari && preg_match('/Version\/[\d\.]+.*Safari/', $userAgent));
        
        if (!$isIosSafari) {
            return [false, []];
        }
        
        return [
            true,
            [
                'playsInline' => true,
                'preload'     => 'metadata',
                'muted'       => true
            ]
        ];
    }

    /**
     * Parse FluentCRM smartcodes in media settings fields.
     * Resolves {{contact.first_name}}, {{crm.business_name}}, etc.
     *
     * @param array|string $settings Media settings array or a single string value
     * @return array|string Settings/string with smartcodes replaced
     */
    public static function parseSmartcodes($settings)
    {
        if (is_string($settings)) {
            if (empty($settings) || !self::containsSmartcode($settings)) {
                return $settings;
            }

            if (!defined('FLUENTCRM') || !function_exists('fluentcrm_get_current_contact')) {
                return self::stripSmartcodes($settings);
            }

            $subscriber = fluentcrm_get_current_contact();
            if (!$subscriber) {
                return self::stripSmartcodes($settings);
            }

            $parsed = apply_filters('fluent_crm/parse_campaign_email_text', $settings, $subscriber);

            if (self::containsSmartcode($parsed)) {
                $parsed = apply_filters('fluent_crm/parse_extended_crm_text', $parsed, $subscriber);
            }

            if (self::containsSmartcode($parsed)) {
                $parsed = self::stripSmartcodes($parsed);
            }

            return $parsed;
        }

        // Early exit: if no smartcodes exist anywhere in the settings, skip traversal
        if (!self::containsSmartcode(json_encode($settings))) {
            return $settings;
        }

        // Top-level text fields that support smartcodes (matches frontend GeneralSettings, etc.)
        $smartcodeFields = ['title'];

        // Nested arrays: each item has these string keys parsed (matches frontend layers/overlays JSX)
        $nestedGroups = [
            'layers'   => ['content', 'title', 'text', 'description', 'button_text', 'button_url', 'url'],
            'overlays' => ['text', 'link'],
        ];

        // Top-level objects with text fields (preset/media email_capture, cta, action_bar – matches PresetEditModal JSX)
        $nestedObjectGroups = [
            'email_capture' => ['placeholder', 'headline', 'button_text', 'bottom_text'],
            'cta'           => ['content'],
            'action_bar'    => ['text', 'button_text', 'button_link'],
        ];

        foreach ($smartcodeFields as $field) {
            if (!empty($settings[$field]) && is_string($settings[$field])) {
                $settings[$field] = self::parseSmartcodes($settings[$field]);
            }
        }

        foreach ($nestedObjectGroups as $groupKey => $fields) {
            if (empty($settings[$groupKey]) || !is_array($settings[$groupKey])) {
                continue;
            }
            foreach ($fields as $field) {
                if (!empty($settings[$groupKey][$field]) && is_string($settings[$groupKey][$field])) {
                    $settings[$groupKey][$field] = self::parseSmartcodes($settings[$groupKey][$field]);
                }
            }
        }

        foreach ($nestedGroups as $groupKey => $fields) {
            if (empty($settings[$groupKey]) || !is_array($settings[$groupKey])) {
                continue;
            }
            foreach ($settings[$groupKey] as &$item) {
                if (!is_array($item)) {
                    continue;
                }
                foreach ($fields as $field) {
                    if (!empty($item[$field]) && is_string($item[$field])) {
                        $item[$field] = self::parseSmartcodes($item[$field]);
                    }
                }
                // Per-layer nested: email_capture (matches EmailLayerSettings JSX)
                if (!empty($item['email_capture']) && is_array($item['email_capture'])) {
                    foreach (['placeholder', 'headline', 'button_text', 'bottom_text'] as $ecField) {
                        if (!empty($item['email_capture'][$ecField]) && is_string($item['email_capture'][$ecField])) {
                            $item['email_capture'][$ecField] = self::parseSmartcodes($item['email_capture'][$ecField]);
                        }
                    }
                }
                // Per-layer nested: hotspots (matches HotspotLayerSettings JSX)
                if (!empty($item['hotspots']) && is_array($item['hotspots'])) {
                    foreach ($item['hotspots'] as &$hotspot) {
                        if (is_array($hotspot)) {
                            if (!empty($hotspot['tooltip_text']) && is_string($hotspot['tooltip_text'])) {
                                $hotspot['tooltip_text'] = self::parseSmartcodes($hotspot['tooltip_text']);
                            }
                            if (!empty($hotspot['link']) && is_string($hotspot['link'])) {
                                $hotspot['link'] = self::parseSmartcodes($hotspot['link']);
                            }
                        }
                    }
                    unset($hotspot);
                }
            }
            unset($item);
        }

        return $settings;
    }

    private static function containsSmartcode($value)
    {
        return strpos($value, '{{') !== false || strpos($value, '##') !== false;
    }

    private static function stripSmartcodes($value)
    {
        return trim(preg_replace('/(\{\{[^}]*\}\}|##[^#]*##)/', '', $value));
    }
}
