<?php

namespace App\Http\Resources;

use App\Facades\Feature;
use App\Facades\Settings;
use App\Facades\Site;
use App\IntegrationRepository;
use App\Modules\PlaceholderImages\ImaginStudio;
use App\Traits\CacheObject;
use App\Traits\RetrievesContent;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
use Mtc\Crm\Models\Form;
use Mtc\MercuryDataModels\Currency;
use Mtc\MercuryDataModels\GlobalContent;
use Mtc\MercuryDataModels\Menu;
use Mtc\MercuryDataModels\SearchFacet;

class SiteResource extends JsonResource
{
    use CacheObject;
    use FranchiseData;
    use PhoneNumberDisplay;
    use RetrievesContent;

    public static $wrap = '';
    private const string UI_RESOURCE_PREFIX = 'App\\Http\\Resources\\';

    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    #[\Override]
    public function toArray($request)
    {
        $integrations = new IntegrationRepository();
        $menus = $this->loadMenus();

        return [
            'id' => tenant('id'),
            'name' => Settings::get('app-name'),
            'locale' => 'en-GB',
            'domain' => Site::siteDomain(),
            'logo' => Settings::get('site-alternate-logo'),
            'contact_phone_number' => $this->displayNumber(Settings::get('app-contact-phone_number') ?? ''),
            'contact_whatsapp_number' => $this->displayNumber(Settings::get('app-contact-whastapp-number') ?? ''),
            'contact_email' => Settings::get('app-contact-contact_email'),
            'currency' => Settings::get('app-details-currency'),
            'favicon' => Settings::get('site-favicon'),
            'apple-touch' => Settings::get('site-apple-touch-icon'),
            'suspended' => tenant('suspended_at'),
            'franchises' => $this->getFranchiseList(),
            'branding' => [
                'primaryColour' => '#' . ltrim((string) Settings::get('app-primary-colour'), '#'),
                'secondaryColour' => '#' . ltrim((string) Settings::get('app-secondary-colour'), '#'),
                'tertiaryColour' => '#' . ltrim((string) Settings::get('app-tertiary-colour'), '#'),
                'successColour' => '#' . ltrim((string) Settings::get('app-success-colour'), '#'),
                'errorColour' => '#' . ltrim((string) Settings::get('app-error-colour'), '#'),
                'informationColour' => '#' . ltrim((string) Settings::get('app-information-colour'), '#'),
                'textColour' => '#' . ltrim((string) Settings::get('app-text-colour'), '#'),
                'subTextColour' => '#' . ltrim((string) Settings::get('app-subtext-colour'), '#'),
                'layerDarkColour' => '#' . ltrim((string) Settings::get('app-layer-dark-colour'), '#'),
                'layerAccentColour' => '#' . ltrim((string) Settings::get('app-layer-accent-colour'), '#'),
                'layerLightColour' => '#' . ltrim((string) Settings::get('app-layer-light-colour'), '#'),
            ],
            'restricted_access' => Settings::get('site-access-enabled'),
            'scripts' => $this->getScripts(),
            'header' => [
                'siteName' => Settings::get('app-name'),
                'logo' => Settings::get('site-logo'),
                'mainMenu' => new MenuResource($menus['header-main'] ?? []),
                'sidebarMenu' => new MenuResource($menus['header-sidebar'] ?? []),
                'franchiseMenu' => new MenuResource($menus['franchise-menu'] ?? []),
            ],
            'cookie_content' => $this->loadGlobal('cookie-consent'),
            'footer' => [
                'logo' => Settings::get('site-logo'),
                'menu' => new MenuResource($menus['footer'] ?? []),
                'copyright' => $this->loadGlobal('copyright'),
                'footer_data' => $this->loadGlobal('footer'),
                'socials' => $integrations->findNonEmptyValuesForType('socials')
                    ->map(fn ($link, $key) => [
                        'key' => $key,
                        'url' => $link,
                    ])->values(),
                'subscribe' => [
                    'enabled' => $integrations->getEnabledForType('newsletters')->isNotEmpty(),
                    'form' => Settings::get('newsletters-form-id')
                        ? new FormViewResource(Form::find(Settings::get('newsletters-form-id')))
                        : null,
                ],
                'calltracks' => Settings::get('crm-calltracks-enabled')
                    ? Settings::get('crm-calltracks-tags')
                    : ''
            ],
            'features' => [
                'vehicle_subscriptions' => Feature::isEnabled('vehicle-subscriptions'),
            ],
            'imagin_studio' => Feature::isEnabled('imagin-studio-placeholders')
                ? new ImaginStudio()->getBaseUrl()
                : null,
            'imagin_studio_tailoring' => Feature::isEnabled('imagin-studio-placeholders')
                ? Settings::get('imagin-placeholders-tailoring')
                : null,
            'liveChat' => $this->liveChat(),
            'distance_measurement' => Settings::get('automotive-distance_measurement'),
            'christmas_enabled' => Settings::get('christmas-enabled'),
            'sitemap_url' => $this->getSitemapUrl(),
            'static_files' => $this->getStaticFiles(),
            'facets' => $this->getFacets(),
            'recaptcha' => [
                // Secret commented out because we do not want to expose this to API endpoint
                // Will be enabled when sites will be migrated over to internalapi for this endpoint
                // 'secret_key' => Settings::get('recaptcha-secret-key'),
                'site_key' => Settings::get('recaptcha-site-key'),
                'threshold' => Settings::get('recaptcha-score-threshold', 0.5),
            ],
            'currency_rates' => $this->getCurrencyRates(),
        ];
    }

    private function getSitemapUrl(): ?string
    {
        if (!Feature::isEnabled('sitemap')) {
            return null;
        }

        $filename = Settings::get('seo-sitemap-split') ? 'sitemap-index.xml' : 'sitemap.xml';
        $disk = Storage::disk('file-storage');
        $path = tenant('id') . '/' . $filename;
        if (!$disk->exists($path)) {
            return null;
        }

        return $this->timestampedUrl($disk, $path);
    }

    /**
     * Aggregate the static files the frontend should expose (sitemaps now, robots.txt etc. later).
     *
     * Files are described with a `type`/`value` pair so consumers can handle both
     * URL-served files (sitemaps) and inline content (e.g. robots.txt) uniformly.
     *
     * @return array<int, array{type: string, value: string}>
     */
    private function getStaticFiles(): array
    {
        return $this->getSitemapStaticFiles();
    }

    /**
     * List every generated sitemap file for the tenant, not just the entry point.
     *
     * In split mode this is `sitemap-index.xml` plus one `sitemap-<section>.xml` per section;
     * in single mode it is just `sitemap.xml`. The generator prunes stale files on each run,
     * so the disk listing is the source of truth and adapts to dynamic section names.
     *
     * @return array<int, array{type: string, value: string}>
     */
    private function getSitemapStaticFiles(): array
    {
        if (!Feature::isEnabled('sitemap')) {
            return [];
        }

        $disk = Storage::disk('file-storage');

        return collect($disk->files(tenant('id')))
            ->filter(fn (string $path) => $this->isSitemapFile(basename($path)))
            ->sortBy(fn (string $path) => basename($path) === 'sitemap-index.xml' ? 0 : 1)
            ->map(fn (string $path) => [
                'type' => 'url',
                'value' => $this->timestampedUrl($disk, $path),
            ])
            ->values()
            ->all();
    }

    private function isSitemapFile(string $basename): bool
    {
        return $basename === 'sitemap.xml'
            || (str_starts_with($basename, 'sitemap-') && str_ends_with($basename, '.xml'));
    }

    private function timestampedUrl(Filesystem $disk, string $path): string
    {
        return $disk->url($path) . '?t=' . $disk->lastModified($path);
    }

    private function getFacets(): array
    {
        if (!Feature::isEnabled('search-facets')) {
            return [];
        }

        return SearchFacet::query()
            ->orderBy('position')
            ->get()
            ->map(fn ($facet) => [
                'position' => $facet->position,
                'filter_type' => $facet->filter_type,
                'robots_index' => $facet->robots_index,
                'robots_follow' => $facet->robots_follow,
            ])
            ->toArray();
    }

    private function liveChat(): ?LiveChatResource
    {
        if ($this->hasLiveChatEnabled() === false) {
            return null;
        }

        return $this->getEnabledLiveChatWidget();
    }

    private function hasLiveChatEnabled(): bool
    {
        return new IntegrationRepository()->getEnabledForType('chat')->isNotEmpty();
    }

    private function getEnabledLiveChatWidget(): LiveChatResource
    {
        return new LiveChatResource(new IntegrationRepository()->getLiveChat());
    }

    private function getScripts(): array
    {
        $scripts = new IntegrationRepository()->getEnabledForType('tracking')
            ->filter(fn ($integration) => $integration['class'])
            ->map(fn ($integration) => App::make($integration['class']))
            ->values()
            ->toArray();

        return collect($scripts)
            ->flatten(1)
            ->toArray();
    }

    private function getCurrencyRates(): ?array
    {
        if (!Feature::isEnabled('multi-currency')) {
            return null;
        }

        return $this->cache('currency-rates', 60, function () {
            $baseCurrency = Settings::get('app-details-currency', 'GBP');
            $currencies = Currency::all();

            $baseRate = $currencies->firstWhere('code', $baseCurrency)?->ratio;
            if (!$baseRate) {
                return null;
            }

            $enabled = Settings::getData('display-currencies')['enabled'] ?? null;

            return $currencies
                ->when(
                    is_array($enabled),
                    fn ($collection) => $collection->filter(
                        fn (Currency $currency) => in_array($currency->code, $enabled, true)
                                || $currency->code === $baseCurrency,
                    ),
                )
                ->map(fn (Currency $currency) => [
                    'code' => $currency->code,
                    'rate' => round($currency->ratio / $baseRate, 6),
                ])
                ->keyBy('code')
                ->toArray();
        });
    }

    private function loadGlobal(string $slug)
    {
        return $this->cache("global-content-$slug", 60, function () use ($slug) {
            /** @var GlobalContent|null $globalContent */
            $globalContent = GlobalContent::query()
                ->with('mediaUses.media')
                ->where('slug', $slug)
                ->first();
            if (!empty($globalContent)) {
                return $this->mapGlobalContent($globalContent);
            } else {
                return null;
            }
        });
    }

    private function loadMenus(): Collection
    {
        return $this->cache("menus", 60, fn () => Menu::query()
            ->with([
                'element.fields',
                'rootEntries' => function ($query) {
                    $query->where('is_enabled', true)
                        ->with([
                            'children' => function ($query) {
                                $query->where('is_enabled', true)
                                    ->with([
                                        'children' => function ($query) {
                                            $query->where('is_enabled', true)
                                                ->with([
                                                    'children' => function ($query) {
                                                        $query->where('is_enabled', true);
                                                    }
                                                ]);
                                        }
                                    ]);
                            }
                        ]);
                },
                'rootEntries.mediaUses.media'
            ])
            ->get()
            ->keyBy('slug'));
    }
}
