<?php

namespace App\Http\Controllers;

use App\Facades\Feature;
use App\Facades\Settings;
use App\Http\Requests\SettingUpdateRequest;
use App\Http\Requests\StoreSettingRequest;
use App\Http\Requests\VerifySettingRequest;
use App\OptionListRepository;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Mtc\ContentManager\Facades\Media;
use Mtc\MercuryDataModels\Audit;
use Mtc\MercuryDataModels\Features\MakesPlaceholderImages;
use Mtc\MercuryDataModels\Setting;
use Mtc\Notifications\Facades\Notification;

class SettingController extends Controller
{
    public function __construct()
    {
        $this->middleware([
            'permission:manage-settings',
        ]);
    }

    /**
     * List all tabs (sections) of the settings area
     *
     * @return \Illuminate\Support\Collection
     */
    public function index()
    {
        return Setting::query()
            ->pluck('tab')
            ->unique()
            ->when(Auth::user()->hasRole('mtc') === false, fn ($query) => $query->whereNull('superadmin'))
            ->merge([
                'Domains',
                'Users',
                'Replacements',
                'Import Maps',
                'Import Conditions',
                'Export Maps',
                Settings::get('filter-use-colour-mapping') ? 'Colour Map' : null,
                !tenant()->live_at ? 'Content Migration' : null,
            ])
            ->filter()
            ->sortBy(fn ($tab) => Settings::tabOrder($tab))
            ->values()
            ->map(fn ($tab) => [
                'name' => $tab,
                'description' => __('settings.tabs.' . $tab),
                'slug' => '/settings/' . Str::slug($tab),
            ]);
    }

    public function search(Request $request)
    {
        $settings = Setting::query()
            ->when(
                $request->filled('term'),
                fn ($query) => $query->where(fn ($termQuery) => $termQuery
                    ->where('config_key', 'like', '%' . $request->input('term') . '%')
                    ->orWhere('name', 'like', '%' . $request->input('term') . '%')
                    ->orWhere('group', 'like', '%' . $request->input('term') . '%')
                    ->orWhere('description', 'like', '%' . $request->input('term') . '%'))
            )
            ->when(Auth::user()->hasRole('mtc') === false, fn ($query) => $query->whereNull('superadmin'))
            ->get()
            ->filter(fn (Setting $setting) => $setting->availableOnTier(tenant()->tier))
            ->filter(fn (Setting $setting) => $setting->hasFeature(tenant()->features->pluck('feature')))
            ->each(fn (Setting $setting) => $setting->setDynamicValues(tenant()->tier));

        return $settings
            ->groupBy(fn ($entry) => Str::slug($entry->section))
            ->map(fn ($section, $slug) => [
                'search' => true,
                'tab' => $section->first()->tab,
                'slug' => '/settings/' . Str::slug($section->first()->tab) . '/' .  $slug,
                'name' => $section->first()->section,
                'allow_order' => Settings::orderableGroups($settings->pluck('group')),
                'description' => $this->getDescription($section->first()->tab, $slug),
                'logo' => $this->sectionLogo($slug),
                'data' => $section
                    ->sortBy('order')
                    ->map(fn ($setting) => [
                        'name' => $setting->group . ' > ' . $setting->name,
                        'value' => in_array($setting->type, ['secret', 'image']) && !empty($setting->value)
                            ? '***'
                            : $setting->value,
                        'config_key' => $setting->config_key,
                    ])
            ])
            ->sortBy(fn ($section, $key) => Settings::sectionOrder($key))
            ->values();
    }

    /**
     * Show Settings for specific section
     *
     * @param string $section
     * @return Builder[]|Collection
     */
    public function show(?string $tab = null)
    {
        if (Feature::isEnabled('makes-placeholders')) {
            MakesPlaceholderImages::populateSettings();
        }

        $settings = Setting::query()
            ->with('mediaUses.media')
            ->when($tab, fn ($query) => $query->where('tab', $tab))
            ->orderBy('order')
            ->when(Auth::user()->hasRole('mtc') === false, fn ($query) => $query->whereNull('superadmin'))
            ->get()
            ->keyBy('config_key');

        // For superadmins, fetch last audit info for each setting
        $lastAudits = [];
        if (Auth::user()->hasRole('mtc')) {
            $settingIds = $settings->pluck('id')->toArray();
            $lastAudits = Audit::query()
                ->where('auditable_type', 'setting')
                ->whereIn('auditable_id', $settingIds)
                ->with('user')
                ->orderByDesc('created_at')
                ->get()
                ->groupBy('auditable_id')
                ->map(fn ($audits) => $audits->first())
                ->keyBy('auditable_id');
        }

        return $settings
            ->filter(fn (Setting $setting) => $setting->availableOnTier(tenant()->tier))
            ->filter(fn (Setting $setting) => $setting->hasFeature(tenant()->features->pluck('feature')))
            ->each(fn (Setting $setting) => $setting->setDynamicValues(tenant()->tier))
            ->each(fn (Setting $setting) => $this->setSourceChoices($setting))
            ->each(function (Setting $setting) use ($lastAudits) {
                if (isset($lastAudits[$setting->id])) {
                    $audit = $lastAudits[$setting->id];
                    $setting->last_edited_by = $audit->user?->name ?? 'System';
                    $setting->last_edited_at = $audit->created_at->format('d/m/Y H:i');
                }
            })
            ->groupBy(fn ($entry) => Str::slug($entry->section))
            ->map(fn ($section, $slug) => [
                'slug' => $slug,
                'name' => $section->first()->section,
                'allow_order' => Settings::orderableGroups($settings->pluck('group')),
                'description' => $this->getDescription($tab, $slug),
                'logo' => $this->sectionLogo($slug),
                'data' => $section
                    ->groupBy('group')
                    ->each(fn ($group) => $group->sortBy('order')),
            ])
            ->sortBy(fn ($section, $key) => Settings::sectionOrder($key))
            ->values();
    }

    public function store(StoreSettingRequest $request): array
    {
        Settings::make([
            'tab' => $request->input('tab'),
            'section' => $request->input('section'),
            'group' => $request->input('group'),
            'name' => $request->input('name'),
            'config_key' => $request->input('config_key'),
            'type' => $request->input('type'),
            'order' => $request->input('order', 99),
            'choices' => $request->input('choices'),
            'description' => $request->input('description'),
            'min_tier' => 'enterprise',
            'validation_rules' => $request->input('validation_rules'),
        ]);

        return [
            'success' => true,
        ];
    }

    /**
     * Store Site setting values of a section
     *
     * @param string $section
     * @param Request $request
     * @return Builder[]|Collection
     */
    public function update(string $section, SettingUpdateRequest $request)
    {
        $settings = Setting::query()
            ->whereIn('config_key', collect($request->input('settings', []))->pluck('config_key'))
            ->get()
            ->keyBy('config_key');

        collect($request->input('settings', []))
            ->filter(fn ($update) => isset($settings[$update['config_key']]))
            ->each(function ($update, $index) use ($settings) {

                $config_key = $update['config_key'];
                $settings[$config_key]->value = (!in_array($settings[$config_key]->type, ['text', 'list']))
                    ? $update['value'] ?? null
                    : null;
                $value_text = '';
                if ($settings[$config_key]->type === 'text') {
                    $value_text = $update['value'] ?? '';
                } elseif ($settings[$config_key]->type === 'list') {
                    $value_text = json_encode($update['value']) ?? '';
                }
                $settings[$config_key]->value_text = $value_text;
                $settings[$config_key]->order = $index;
                $settings[$config_key]->save();
                if ($settings[$config_key]->type === 'media') {
                    $media = isset($update['value']) ? [$update['value']] : [];

                    // for makes placeholders
                    $sizesKey = $config_key;
                    if (Str::contains($config_key, 'placeholder-image-vehicle')) {
                        $sizesKey = 'placeholder-image-vehicle';
                    }

                    Media::setUsesForModel(
                        $media,
                        $settings[$config_key],
                        ['allowed_sizes' => config(config("automotive.placeholder_media_sizes.$sizesKey"))]
                    );
                }
            });
        Cache::forget(tenant('id') . '-settings');
        Cache::forget(tenant('id') . '-get-site');
        return $this->show($section);
    }

    public function triggerAction(Request $request): Response
    {
        try {
            Settings::triggerAction($request->input('key'));
            Notification::addNotification(
                'info',
                Auth::user()->name . ' called system action: ' . str_replace('-', ' ', $request->input('key')),
                [],
                'edit-vehicles',
                '',
            );
            return \response('Action triggered');
        } catch (\Exception $exception) {
            throw ValidationException::withMessages([$exception->getMessage()]);
        }
    }

    /**
     * Verify a setting
     *
     * @param VerifySettingRequest $request
     * @return Builder[]|Collection
     */
    public function verify(VerifySettingRequest $request)
    {
        $result = Settings::verify($request->input('verify_check'));
        if ($result instanceof Response) {
            return $result;
        }
        return $this->show($request->input('tab'));
    }

    private function sectionLogo($slug): ?string
    {
        return match ($slug) {
            'autotrader' => config('app.url') . '/api/assets/auto-trader.png',
            default => null,
        };
    }

    private function getDescription(string $tab, string $slug): string
    {
        if ($slug === 'general') {
            $slug .= '-' . $tab;
        }

        return Lang::has("settings.descriptions.$slug")
            ? __("settings.descriptions.$slug")
            : '';
    }

    private function setSourceChoices(Setting $setting)
    {
        if (!empty($setting->source)) {
            $setting->choices = new OptionListRepository()->getForType($setting->source, \request());
        }
    }
}
