<?php

namespace App\Http\Livewire\Calls;

use App\Helpers\StringHelper;
use App\Jobs\SendEmailNewTag;
use App\Models\Category;
use App\Models\Language;
use App\Models\Tag;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Livewire\Component;

class CallSkillInput extends Component
{
    // Tagify state
    public string $tagsArray = '[]';
    public array $suggestions = [];

    // New tag creation modal
    public bool $modalVisible = false;
    public array $newTag = ['name' => ''];
    public ?int $newTagCategory = null;
    public array $categoryOptions = [];
    public string $categoryColor = 'gray';

    // Language detection
    public bool $sessionLanguageOk = false;
    public bool $sessionLanguageIgnored = false;
    public bool $transLanguageOk = false;
    public bool $transLanguageIgnored = false;

    // Translation support
    public bool $translationPossible = true;
    public bool $translationAllowed = true;
    public bool $translationVisible = false;
    public array $translationLanguages = [];
    public $selectTranslationLanguage = null;
    public array $translationOptions = [];
    public $selectTagTranslation = null;
    public array $inputTagTranslation = [];
    public bool $inputDisabled = true;
    public $translateRadioButton = null;

    protected $langDetector = null;

    protected function rules(): array
    {
        return $this->createTagValidationRules();
    }

    public ?int $initialTagId = null;

    public function mount(?int $initialTagId = null): void
    {
        $this->initialTagId = $initialTagId;

        if ($initialTagId) {
            $tag = \App\Models\Tag::find($initialTagId);
            if ($tag) {
                $color = $tag->contexts->first()?->category?->relatedColor ?? 'gray';
                $tagDisplayName = $tag->translation?->name ?? $tag->name;
                $this->tagsArray = json_encode([[
                    'value'  => $tagDisplayName,
                    'tag_id' => $tag->tag_id,
                    'title'  => $tagDisplayName,
                    'style'  => '--tag-bg:' . tailwindColorToHex($color . '-400') . '; --tag-text-color:#000; --tag-hover:' . tailwindColorToHex($color . '-200'),
                ]]);
            }
        }

        $this->suggestions = $this->getSuggestions();
        $this->checkTranslationAllowed();
        $this->checkTranslationPossible();
    }

    protected function getSuggestions(): array
    {
        return DB::table('taggable_tags as tt')
            ->join('taggable_locales as tl', 'tt.tag_id', '=', 'tl.taggable_tag_id')
            ->join('taggable_locale_context as tlc', 'tt.tag_id', '=', 'tlc.tag_id')
            ->join('taggable_contexts as tc', 'tlc.context_id', '=', 'tc.id')
            ->join('categories as c', 'tc.category_id', '=', 'c.id')
            ->join('categories as croot', DB::raw('COALESCE(c.parent_id, c.id)'), '=', 'croot.id')
            ->where('tl.locale', app()->getLocale())
            ->select('tt.tag_id', 'tt.name', 'croot.color')
            ->distinct()
            ->orderBy('tt.name')
            ->get()
            ->map(function ($t) {
                $color = $t->color ?? 'gray';
                return [
                    'value'  => $t->name,
                    'tag_id' => $t->tag_id,
                    'style'  => '--tag-bg:' . tailwindColorToHex($color . '-400') . '; --tag-text-color:#000; --tag-hover:' . tailwindColorToHex($color . '-200'),
                    'title'  => $t->name,
                ];
            })
            ->values()
            ->toArray();
    }

    /**
     * Called from Alpine when the user selects a known tag from the whitelist.
     * Notifies the parent Create component.
     */
    public function notifyTagSelected(int $tagId): void
    {
        $this->dispatch('callTagSelected', tagId: $tagId);
    }

    /**
     * Called from Alpine when the tag is removed (input cleared).
     */
    public function notifyTagCleared(): void
    {
        $this->dispatch('callTagCleared');
    }

    /**
     * Called from Alpine when the user types an unknown tag name and confirms it.
     */
    public function openNewTagModal(string $name): void
    {
        $this->newTag['name']  = $name;
        $this->categoryOptions = $this->loadCategoryOptions();
        $this->modalVisible    = true;
        $this->checkSessionLanguage();
    }

    protected function loadCategoryOptions(): array
    {
        return Category::where('type', Tag::class)
            ->get()
            ->map(function ($category) {
                return [
                    'category_id' => $category->id,
                    'name'        => ucfirst($category->translation->name ?? ''),
                    'description' => $category->relatedPathExSelfTranslation ?? '',
                    'color'       => $category->relatedColor ?? 'gray',
                ];
            })
            ->sortBy('name')
            ->values()
            ->toArray();
    }

    public function checkTranslationAllowed(): void
    {
        $allowTranslations = timebank_config('tags.allow_tag_transations_for_non_admins', false);
        $profileType = getActiveProfileType();

        if (!$allowTranslations) {
            $this->translationAllowed = ($profileType === 'admin');
        } else {
            $this->translationAllowed = true;
        }
    }

    public function checkTranslationPossible(): void
    {
        $profile = getActiveProfile();
        if (!$profile || !method_exists($profile, 'languages')) {
            $this->translationPossible = false;
            return;
        }
        $countNonBaseLanguages = $profile->languages()->where('lang_code', '!=', timebank_config('base_language'))->count();
        if ($countNonBaseLanguages === 0 && app()->getLocale() === timebank_config('base_language')) {
            $this->translationPossible = false;
        }
    }

    protected function getLanguageDetector()
    {
        if (!$this->langDetector) {
            $this->langDetector = new \Text_LanguageDetect();
            $this->langDetector->setNameMode(2);
        }
        return $this->langDetector;
    }

    public function checkSessionLanguage(): void
    {
        $this->getLanguageDetector();
        $detectedLanguage = $this->langDetector->detectSimple($this->newTag['name'] ?? '');
        if ($detectedLanguage === session('locale')) {
            $this->sessionLanguageOk = true;
            $this->sessionLanguageIgnored = false;
        } else {
            $this->sessionLanguageOk = false;
        }
        $this->validateOnly('newTag.name');
    }

    public function checkTransLanguage(): void
    {
        $this->getLanguageDetector();
        $detectedLanguage = $this->langDetector->detectSimple($this->inputTagTranslation['name'] ?? '');
        if ($detectedLanguage === $this->selectTranslationLanguage) {
            $this->transLanguageOk = true;
            $this->transLanguageIgnored = false;
        } else {
            $this->transLanguageOk = false;
        }
        $this->validateOnly('inputTagTranslation.name');
    }

    public function updatedNewTagCategory(): void
    {
        $this->categoryColor = collect($this->categoryOptions)
            ->firstWhere('category_id', $this->newTagCategory)['color'] ?? 'gray';
        $this->selectTagTranslation = null;
        $this->translationOptions = $this->getTranslationOptions($this->selectTranslationLanguage);
        $this->resetErrorBag('inputTagTranslationCategory');
    }

    public function updatedSessionLanguageIgnored(): void
    {
        if (!$this->sessionLanguageIgnored) {
            $this->checkSessionLanguage();
        }
        $this->validateOnly('newTag.name');
    }

    public function updatedTransLanguageIgnored(): void
    {
        if (!$this->transLanguageIgnored) {
            $this->checkTransLanguage();
        } else {
            $this->resetErrorBag('inputTagTranslation.name');
        }
    }

    public function updatedSelectTranslationLanguage(): void
    {
        $this->selectTagTranslation = null;
        $this->translationOptions = $this->getTranslationOptions($this->selectTranslationLanguage);
    }

    public function updatedTranslationVisible(): void
    {
        if ($this->translationVisible && $this->translationAllowed) {
            $this->updatedNewTagCategory();

            $profile = getActiveProfile();
            if (!$profile || !method_exists($profile, 'languages')) {
                return;
            }

            \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

            $this->translationLanguages = $profile
                ->languages()
                ->wherePivot('competence', 1)
                ->where('lang_code', '!=', app()->getLocale())
                ->get()
                ->map(function ($language) {
                    $language->name = trans($language->name);
                    return $language;
                })
                ->toArray();

            if (!collect($this->translationLanguages)->contains('lang_code', 'en')) {
                $transLanguage = Language::where('lang_code', timebank_config('base_language'))->first();
                if ($transLanguage) {
                    $transLanguage->name = trans($transLanguage->name);
                    $this->translationLanguages = collect($this->translationLanguages)->push($transLanguage)->toArray();
                }
                if (app()->getLocale() != timebank_config('base_language')) {
                    $this->selectTranslationLanguage = timebank_config('base_language');
                }
            }
        }
    }

    public function updatedTranslateRadioButton(): void
    {
        if ($this->translateRadioButton === 'select') {
            $this->inputDisabled = true;
            $this->dispatch('disableInput');
        } elseif ($this->translateRadioButton === 'input') {
            $this->inputDisabled = false;
        }
        $this->resetErrorBag('selectTagTranslation');
        $this->resetErrorBag('inputTagTranslation.name');
        $this->resetErrorBag('newTagCategory');
    }

    public function updatedSelectTagTranslation(): void
    {
        if ($this->selectTagTranslation) {
            $this->categoryColor = Tag::find($this->selectTagTranslation)->categories->first()->relatedColor ?? 'gray';
            $this->translateRadioButton = 'select';
            $this->dispatch('disableInput');
        }
    }

    public function updatedInputTagTranslation(): void
    {
        $this->translateRadioButton = 'input';
        $this->inputDisabled = false;
        $this->checkTransLanguage();
    }

    public function getTranslationOptions(?string $locale): array
    {
        if (!$locale) {
            return [];
        }

        $appLocale = app()->getLocale();

        $contextIdsInAppLocale = DB::table('taggable_locale_context')
            ->whereIn('tag_id', function ($query) use ($appLocale) {
                $query->select('taggable_tag_id')
                    ->from('taggable_locales')
                    ->where('locale', $appLocale);
            })
            ->pluck('context_id');

        $tags = Tag::with(['locale', 'contexts.category'])
            ->whereHas('locale', function ($query) use ($locale) {
                $query->where('locale', $locale);
            })
            ->whereNotIn('tag_id', function ($subquery) use ($contextIdsInAppLocale) {
                $subquery->select('tag_id')
                    ->from('taggable_locale_context')
                    ->whereIn('context_id', $contextIdsInAppLocale);
            })
            ->get();

        return $tags->map(function ($tag) use ($locale) {
            $category = optional($tag->contexts->first())->category;
            $description = optional(optional($category)->translation)->name ?? '';
            return [
                'tag_id'      => $tag->tag_id,
                'name'        => $locale == 'de' ? $tag->name : StringHelper::DutchTitleCase($tag->normalized),
                'description' => $description,
            ];
        })->sortBy('name')->values()->toArray();
    }

    protected function createTagValidationRules(): array
    {
        return [
            'newTag.name' => array_merge(
                timebank_config('tags.name_rule'),
                timebank_config('tags.exists_in_current_locale_rule', []),
                [
                    'sometimes',
                    function ($attribute, $value, $fail) {
                        if (!$this->sessionLanguageOk && !$this->sessionLanguageIgnored) {
                            $locale = app()->getLocale();
                            $localeName = \Locale::getDisplayName($locale, $locale);
                            $fail(__('Is this :locale? Please confirm here below', ['locale' => $localeName]));
                        }
                    },
                ]
            ),
            'newTagCategory' => function () {
                if ($this->translationVisible && $this->translateRadioButton == 'input') {
                    return 'required|int';
                }
                if (!$this->translationVisible) {
                    return 'required|int';
                }
                return 'nullable';
            },
            'selectTagTranslation' => ($this->translationVisible && $this->translateRadioButton == 'select')
                ? 'required|int'
                : 'nullable',
            'inputTagTranslation.name' => ($this->translationVisible && $this->translateRadioButton === 'input')
                ? array_merge(
                    timebank_config('tags.name_rule'),
                    timebank_config('tags.exists_in_current_locale_rule', []),
                    [
                        'sometimes',
                        function ($attribute, $value, $fail) {
                            if (!$this->transLanguageOk && !$this->transLanguageIgnored) {
                                $baseLocale = $this->selectTranslationLanguage;
                                $locale = \Locale::getDisplayName($baseLocale, $baseLocale);
                                $fail(__('Is this :locale? Please confirm here below', ['locale' => $locale]));
                            }
                        },
                        function ($attribute, $value, $fail) {
                            $existsInTransLationLanguage = DB::table('taggable_tags')
                                ->join('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
                                ->where('taggable_locales.locale', $this->selectTranslationLanguage)
                                ->where(function ($query) use ($value) {
                                    $query->where('taggable_tags.name', $value)
                                        ->orWhere('taggable_tags.normalized', $value);
                                })
                                ->exists();
                            if ($existsInTransLationLanguage) {
                                $fail(__('This tag already exists.'));
                            }
                        },
                    ]
                )
                : 'nullable',
        ];
    }

    public function createTag(): void
    {
        $this->validate($this->createTagValidationRules());
        $this->resetErrorBag();

        $name = app()->getLocale() == 'de'
            ? trim($this->newTag['name'])
            : StringHelper::DutchTitleCase(trim($this->newTag['name']));
        $normalized = call_user_func(config('taggable.normalizer'), $name);

        $existing = Tag::whereHas('locale', fn ($q) => $q->where('locale', app()->getLocale()))
            ->where('name', $name)
            ->first();

        if ($existing) {
            $tag = $existing;
        } else {
            $tag = Tag::create(['name' => $name, 'normalized' => $normalized]);
            $tag->locale()->create(['locale' => app()->getLocale()]);
        }

        $context = [
            'category_id'     => $this->newTagCategory,
            'updated_by_user' => Auth::guard('web')->id(),
        ];

        if ($this->translationVisible) {
            if ($this->translateRadioButton === 'select') {
                $tagContext = Tag::find($this->selectTagTranslation)->contexts()->first();
                $tag->contexts()->attach($tagContext->id);
            } elseif ($this->translateRadioButton === 'input') {
                $tagContext = $tag->contexts()->create($context);

                $this->inputTagTranslation['name'] = $this->selectTranslationLanguage == 'de'
                    ? $this->inputTagTranslation['name']
                    : StringHelper::DutchTitleCase($this->inputTagTranslation['name']);

                $nameTranslation = $this->inputTagTranslation['name'];
                $normalizedTranslation = call_user_func(config('taggable.normalizer'), $nameTranslation);

                $tagTranslation = Tag::create([
                    'name'       => $nameTranslation,
                    'normalized' => $normalizedTranslation,
                ]);
                $tagTranslation->locale()->create(['locale' => $this->selectTranslationLanguage]);
                $tagTranslation->contexts()->attach($tagContext->id);
            }
        } else {
            if (!$tag->contexts()->where('category_id', $this->newTagCategory)->exists()) {
                $tag->contexts()->create($context);
            }
        }

        $color = collect($this->categoryOptions)->firstWhere('category_id', $this->newTagCategory)['color'] ?? 'gray';
        $this->tagsArray = json_encode([[
            'value'  => $tag->translation?->name ?? $tag->name,
            'tag_id' => $tag->tag_id,
            'title'  => $name,
            'style'  => '--tag-bg:' . tailwindColorToHex($color . '-400') . '; --tag-text-color:#000; --tag-hover:' . tailwindColorToHex($color . '-200'),
        ]]);

        $this->modalVisible         = false;
        $this->newTag               = ['name' => ''];
        $this->newTagCategory       = null;
        $this->categoryColor        = 'gray';
        $this->translationVisible   = false;
        $this->translateRadioButton = null;
        $this->selectTagTranslation = null;
        $this->inputTagTranslation  = [];
        $this->sessionLanguageOk    = false;
        $this->sessionLanguageIgnored = false;
        $this->transLanguageOk      = false;
        $this->transLanguageIgnored = false;
        $this->resetErrorBag(['newTag.name', 'newTagCategory']);

        // Reload Tagify badge in this component's input
        $this->dispatch('callTagifyReload', tagsArray: $this->tagsArray);

        // Notify parent (Create or Edit) of the selected tag
        $this->dispatch('callTagSelected', tagId: $tag->tag_id);

        SendEmailNewTag::dispatch($tag->tag_id);
    }

    public function cancelCreateTag(): void
    {
        $this->resetErrorBag();
        $this->newTag               = ['name' => ''];
        $this->newTagCategory       = null;
        $this->categoryColor        = 'gray';
        $this->modalVisible         = false;
        $this->translationVisible   = false;
        $this->translateRadioButton = null;
        $this->selectTagTranslation = null;
        $this->inputTagTranslation  = [];
        $this->sessionLanguageOk    = false;
        $this->sessionLanguageIgnored = false;
        $this->transLanguageOk      = false;
        $this->transLanguageIgnored = false;
        $this->dispatch('removeLastCallTag');
    }

    public function render()
    {
        return view('livewire.calls.call-skill-input');
    }
}
