<?php

namespace App\Http\Controllers\Admin;

use App\CentralLogics\Helpers;
use App\Http\Controllers\Controller;
use App\Models\AiCorrection;
use App\Models\ChatFaq;
use App\Models\ChatLog;
use App\Models\ChatOffer;
use App\Models\ExternalChatMessage;
use App\Models\ExternalChatSession;
use App\Models\KnowledgeBaseEntry;
use App\Services\AiChat\AiChatService;
use App\Services\AiChat\AiProductIndexService;
use App\Services\AiChat\MetaChatSettingsService;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;

class AiChatBoardController extends Controller
{
    public function __construct(
        private readonly AiChatService $aiChatService,
        private readonly AiProductIndexService $aiProductIndexService,
        private readonly MetaChatSettingsService $metaChatSettingsService
    )
    {
    }

    public function index(Request $request): View
    {
        $perPage = (int) (config('default_pagination') ?: 10);
        $hasKnowledgeBase = $this->hasTable('knowledge_base');
        $hasSourceCategory = $hasKnowledgeBase && $this->hasColumn('knowledge_base', 'source_category');

        $keywordEntries = $hasSourceCategory
            ? KnowledgeBaseEntry::query()->where('source_category', 'keyword')->orderByDesc('priority')->latest('updated_at')->paginate($perPage, ['*'], 'keyword_page')
            : $this->emptyPaginator($request, 'keyword_page', $perPage);

        $knowledgeEntries = $hasKnowledgeBase
            ? KnowledgeBaseEntry::query()
                ->when($hasSourceCategory, fn ($query) => $query->where('source_category', '!=', 'keyword'))
                ->latest('updated_at')
                ->paginate($perPage, ['*'], 'knowledge_page')
            : $this->emptyPaginator($request, 'knowledge_page', $perPage);

        $offers = $this->hasTable('offers')
            ? ChatOffer::query()->latest('updated_at')->paginate($perPage, ['*'], 'offer_page')
            : $this->emptyPaginator($request, 'offer_page', $perPage);

        $faqs = $this->hasTable('faq')
            ? ChatFaq::query()->latest('updated_at')->paginate($perPage, ['*'], 'faq_page')
            : $this->emptyPaginator($request, 'faq_page', $perPage);

        $corrections = $this->hasTable('ai_corrections')
            ? AiCorrection::query()->latest('updated_at')->paginate($perPage, ['*'], 'correction_page')
            : $this->emptyPaginator($request, 'correction_page', $perPage);

        $logs = $this->hasTable('chat_logs')
            ? ChatLog::query()->latest('created_at')->paginate($perPage, ['*'], 'log_page')
            : $this->emptyPaginator($request, 'log_page', $perPage);

        $channelSettings = $this->metaChatSettingsService->getSettings();
        if (blank(data_get($channelSettings, 'whatsapp.verify_token'))) {
            $channelSettings['whatsapp']['verify_token'] = Str::random(48);
        }
        if (blank(data_get($channelSettings, 'messenger.verify_token'))) {
            $channelSettings['messenger']['verify_token'] = Str::random(48);
        }

        return view('admin-views.business-settings.settings.ai-chat-board', [
            'settings' => $this->aiChatService->settings(),
            'channelSettings' => $channelSettings,
            'keywordEntries' => $keywordEntries,
            'knowledgeEntries' => $knowledgeEntries,
            'offers' => $offers,
            'faqs' => $faqs,
            'corrections' => $corrections,
            'logs' => $logs,
            'externalSessionCount' => Schema::hasTable('external_chat_sessions') ? ExternalChatSession::query()->count() : 0,
            'externalMessageCount' => Schema::hasTable('external_chat_messages') ? ExternalChatMessage::query()->count() : 0,
            'editKeyword' => $hasSourceCategory && $request->filled('edit_keyword')
                ? KnowledgeBaseEntry::findOrFail((int) $request->edit_keyword)
                : null,
            'editKnowledge' => $hasKnowledgeBase && $request->filled('edit_knowledge')
                ? KnowledgeBaseEntry::findOrFail((int) $request->edit_knowledge)
                : null,
            'editOffer' => $this->hasTable('offers') && $request->filled('edit_offer')
                ? ChatOffer::findOrFail((int) $request->edit_offer)
                : null,
            'editFaq' => $this->hasTable('faq') && $request->filled('edit_faq')
                ? ChatFaq::findOrFail((int) $request->edit_faq)
                : null,
            'editCorrection' => $this->hasTable('ai_corrections') && $request->filled('edit_correction')
                ? AiCorrection::findOrFail((int) $request->edit_correction)
                : null,
        ]);
    }

    public function syncProducts(Request $request): RedirectResponse
    {
        $synced = $this->aiProductIndexService->syncAllProducts();

        Toastr::success(translate('AI product knowledge synced successfully') . " ({$synced})");
        return redirect()->back();
    }

    public function syncPages(Request $request): RedirectResponse
    {
        $synced = $this->aiProductIndexService->syncPolicyPages();

        Toastr::success(translate('AI policy/page knowledge synced successfully') . " ({$synced})");
        return redirect()->back();
    }

    public function knowledgeFeed(Request $request): JsonResponse
    {
        if (!$this->hasTable('knowledge_base')) {
            return response()->json(['data' => []]);
        }

        return response()->json([
            'data' => $this->aiChatService->knowledgeFeed([
                'active_only' => $request->boolean('active_only'),
                'search' => $request->string('search')->toString(),
            ]),
        ]);
    }

    public function offersFeed(Request $request): JsonResponse
    {
        if (!$this->hasTable('offers')) {
            return response()->json(['data' => []]);
        }

        return response()->json([
            'data' => $this->aiChatService->offersFeed([
                'active_only' => $request->boolean('active_only'),
                'search' => $request->string('search')->toString(),
            ]),
        ]);
    }

    public function updateSettings(Request $request): RedirectResponse
    {
        foreach ([
            'ai_chat_board_enabled',
            'ai_chat_auto_reply_enabled',
            'ai_chat_offer_module_enabled',
            'ai_chat_faq_enabled',
            'ai_chat_knowledge_enabled',
            'ai_chat_correction_approval_enabled',
            'ai_chat_sales_mode_enabled',
            'ai_chat_product_recommendation_enabled',
            'ai_chat_image_search_enabled',
            'ai_chat_verified_reply_only',
        ] as $key) {
            Helpers::businessUpdateOrInsert(['key' => $key], [
                'value' => $request->boolean($key) ? 1 : 0,
            ]);
        }

        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_answer_priority_order'], [
            'value' => $request->input('ai_chat_answer_priority_order', 'correction,knowledge,faq,offer,product,policy'),
        ]);
        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_reply_language'], [
            'value' => in_array($request->input('ai_chat_reply_language'), ['auto', 'bn', 'en'], true)
                ? $request->input('ai_chat_reply_language')
                : 'auto',
        ]);
        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_custom_instruction'], [
            'value' => $request->input('ai_chat_custom_instruction', ''),
        ]);
        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_fallback_message_bn'], [
            'value' => $request->input('ai_chat_fallback_message_bn', 'এই তথ্যটি আমি নিশ্চিতভাবে খুঁজে পাইনি, অনুগ্রহ করে product name/model দিন।'),
        ]);
        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_fallback_message_en'], [
            'value' => $request->input('ai_chat_fallback_message_en', 'I could not verify that information. Please share the product name/model.'),
        ]);

        $threshold = max(0, min(100, (int) $request->input('ai_chat_product_match_threshold', 0)));
        Helpers::businessUpdateOrInsert(['key' => 'ai_chat_product_match_threshold'], [
            'value' => $threshold,
        ]);

        Toastr::success(translate('AI chat board settings updated successfully'));
        return $this->redirectToBoard('settings-section');
    }

    public function updateChannelSettings(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'meta_channels_enabled' => 'nullable|boolean',
            'meta_graph_version' => ['required', 'string', 'max:20', 'regex:/^v[0-9]+\\.[0-9]+$/'],
            'whatsapp_enabled' => 'nullable|boolean',
            'whatsapp_verify_token' => 'required|string|max:191',
            'whatsapp_access_token' => 'nullable|string|max:4000',
            'whatsapp_phone_number_id' => 'nullable|string|max:191',
            'whatsapp_business_account_id' => 'nullable|string|max:191',
            'messenger_enabled' => 'nullable|boolean',
            'messenger_verify_token' => 'required|string|max:191',
            'messenger_page_access_token' => 'nullable|string|max:4000',
            'messenger_page_id' => 'nullable|string|max:191',
        ]);

        $this->metaChatSettingsService->saveSettings($validated);

        Toastr::success(translate('Meta channel settings updated successfully'));
        return $this->redirectToBoard('channel-section');
    }

    public function storeKnowledge(Request $request): RedirectResponse
    {
        $data = $this->validateKnowledge($request);
        $normalizedKey = $this->makeNormalizedKey("{$data['title']} {$data['question_patterns']}");

        $this->ensureUnique(KnowledgeBaseEntry::query(), 'normalized_key', $normalizedKey);

        KnowledgeBaseEntry::query()->create($data + [
            'normalized_key' => $normalizedKey,
            'created_by_admin_id' => auth('admin')->id(),
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Knowledge entry added successfully'));
        return $this->redirectToBoard('knowledge-section');
    }

    public function updateKnowledge(Request $request, KnowledgeBaseEntry $knowledgeBase): RedirectResponse
    {
        $data = $this->validateKnowledge($request, true);
        $normalizedKey = $this->makeNormalizedKey("{$data['title']} {$data['question_patterns']}");

        $this->ensureUnique(KnowledgeBaseEntry::query()->where('id', '!=', $knowledgeBase->id), 'normalized_key', $normalizedKey);

        $knowledgeBase->update($data + [
            'normalized_key' => $normalizedKey,
            'version' => $knowledgeBase->version + 1,
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Knowledge entry updated successfully'));
        return $this->redirectToBoard('knowledge-section');
    }

    public function knowledgeStatus(KnowledgeBaseEntry $knowledgeBase, int $status): RedirectResponse
    {
        $knowledgeBase->update(['is_active' => (bool) $status]);
        Toastr::success(translate('Status updated'));
        return $this->redirectToBoard('knowledge-section');
    }

    public function destroyKnowledge(KnowledgeBaseEntry $knowledgeBase): RedirectResponse
    {
        $knowledgeBase->delete();
        Toastr::success(translate('Knowledge entry deleted successfully'));
        return $this->redirectToBoard('knowledge-section');
    }

    public function storeOffer(Request $request): RedirectResponse
    {
        $data = $this->validateOffer($request);
        $slug = Str::slug($data['title']);
        $this->ensureUnique(ChatOffer::query(), 'slug', $slug);

        ChatOffer::query()->create($data + [
            'slug' => $slug,
            'created_by_admin_id' => auth('admin')->id(),
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Offer added successfully'));
        return $this->redirectToBoard('offer-section');
    }

    public function updateOffer(Request $request, ChatOffer $offer): RedirectResponse
    {
        $data = $this->validateOffer($request, true);
        $slug = Str::slug($data['title']);
        $this->ensureUnique(ChatOffer::query()->where('id', '!=', $offer->id), 'slug', $slug);

        $offer->update($data + [
            'slug' => $slug,
            'version' => $offer->version + 1,
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Offer updated successfully'));
        return $this->redirectToBoard('offer-section');
    }

    public function offerStatus(ChatOffer $offer, int $status): RedirectResponse
    {
        $offer->update(['is_active' => (bool) $status]);
        Toastr::success(translate('Status updated'));
        return $this->redirectToBoard('offer-section');
    }

    public function destroyOffer(ChatOffer $offer): RedirectResponse
    {
        $offer->delete();
        Toastr::success(translate('Offer deleted successfully'));
        return $this->redirectToBoard('offer-section');
    }

    public function storeFaq(Request $request): RedirectResponse
    {
        $data = $this->validateFaq($request);
        $normalizedKey = $this->makeNormalizedKey($data['question']);

        $this->ensureUnique(ChatFaq::query(), 'normalized_key', $normalizedKey);

        ChatFaq::query()->create($data + [
            'normalized_key' => $normalizedKey,
            'created_by_admin_id' => auth('admin')->id(),
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('FAQ added successfully'));
        return $this->redirectToBoard('faq-section');
    }

    public function updateFaq(Request $request, ChatFaq $faq): RedirectResponse
    {
        $data = $this->validateFaq($request, true);
        $normalizedKey = $this->makeNormalizedKey($data['question']);

        $this->ensureUnique(ChatFaq::query()->where('id', '!=', $faq->id), 'normalized_key', $normalizedKey);

        $faq->update($data + [
            'normalized_key' => $normalizedKey,
            'version' => $faq->version + 1,
            'updated_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('FAQ updated successfully'));
        return $this->redirectToBoard('faq-section');
    }

    public function faqStatus(ChatFaq $faq, int $status): RedirectResponse
    {
        $faq->update(['is_active' => (bool) $status]);
        Toastr::success(translate('Status updated'));
        return $this->redirectToBoard('faq-section');
    }

    public function destroyFaq(ChatFaq $faq): RedirectResponse
    {
        $faq->delete();
        Toastr::success(translate('FAQ deleted successfully'));
        return $this->redirectToBoard('faq-section');
    }

    public function storeCorrection(Request $request): RedirectResponse
    {
        $data = $this->validateCorrection($request);
        $normalizedQuestion = $this->makeNormalizedKey($data['question']);
        $this->ensureUnique(AiCorrection::query(), 'normalized_question', $normalizedQuestion);

        AiCorrection::query()->create($data + [
            'normalized_question' => $normalizedQuestion,
            'corrected_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Correction added successfully'));
        return $this->redirectToBoard('correction-section');
    }

    public function updateCorrection(Request $request, AiCorrection $correction): RedirectResponse
    {
        $data = $this->validateCorrection($request, true);
        $normalizedQuestion = $this->makeNormalizedKey($data['question']);
        $this->ensureUnique(AiCorrection::query()->where('id', '!=', $correction->id), 'normalized_question', $normalizedQuestion);

        $correction->update($data + [
            'normalized_question' => $normalizedQuestion,
            'version' => $correction->version + 1,
            'corrected_by_admin_id' => auth('admin')->id(),
        ]);

        Toastr::success(translate('Correction updated successfully'));
        return $this->redirectToBoard('correction-section');
    }

    public function correctionStatus(AiCorrection $correction, int $status): RedirectResponse
    {
        $correction->update(['is_active' => (bool) $status]);
        Toastr::success(translate('Status updated'));
        return $this->redirectToBoard('correction-section');
    }

    public function correctionApproval(AiCorrection $correction, int $status): RedirectResponse
    {
        $correction->update(['is_approved' => (bool) $status]);
        Toastr::success(translate('Correction approval updated'));
        return $this->redirectToBoard('correction-section');
    }

    public function destroyCorrection(AiCorrection $correction): RedirectResponse
    {
        $correction->delete();
        Toastr::success(translate('Correction deleted successfully'));
        return $this->redirectToBoard('correction-section');
    }

    protected function validateKnowledge(Request $request, bool $updating = false): array
    {
        return $request->validate([
            'title' => 'required|string|max:191',
            'source_category' => 'required|string|max:40',
            'question_patterns' => 'nullable|string|max:500',
            'tags' => 'nullable|string|max:255',
            'answer_bn' => 'nullable|string',
            'answer_en' => 'nullable|string',
            'priority' => 'nullable|integer|min:0|max:9999',
            'is_active' => 'nullable|boolean',
        ]) + [
            'answer' => $request->input('answer_en') ?: $request->input('answer_bn'),
            'priority' => (int) ($request->input('priority') ?? 0),
            'is_active' => $request->boolean('is_active'),
            'version' => $updating ? (int) $request->input('version', 1) : 1,
        ];
    }

    protected function validateOffer(Request $request, bool $updating = false): array
    {
        return $request->validate([
            'title' => 'required|string|max:191',
            'description' => 'nullable|string',
            'title_bn' => 'nullable|string|max:191',
            'title_en' => 'nullable|string|max:191',
            'description_bn' => 'nullable|string',
            'description_en' => 'nullable|string',
            'start_date' => 'nullable|date',
            'end_date' => 'nullable|date|after_or_equal:start_date',
            'priority' => 'nullable|integer|min:0|max:9999',
            'is_active' => 'nullable|boolean',
        ]) + [
            'priority' => (int) ($request->input('priority') ?? 0),
            'is_active' => $request->boolean('is_active'),
            'version' => $updating ? (int) $request->input('version', 1) : 1,
        ];
    }

    protected function validateFaq(Request $request, bool $updating = false): array
    {
        return $request->validate([
            'question' => 'required|string|max:191',
            'question_bn' => 'nullable|string|max:500',
            'question_en' => 'nullable|string|max:500',
            'answer_bn' => 'nullable|string',
            'answer_en' => 'nullable|string',
            'priority' => 'nullable|integer|min:0|max:9999',
            'is_active' => 'nullable|boolean',
        ]) + [
            'answer' => $request->input('answer_en') ?: $request->input('answer_bn'),
            'priority' => (int) ($request->input('priority') ?? 0),
            'is_active' => $request->boolean('is_active'),
            'version' => $updating ? (int) $request->input('version', 1) : 1,
        ];
    }

    protected function validateCorrection(Request $request, bool $updating = false): array
    {
        return $request->validate([
            'question' => 'required|string|max:191',
            'question_bn' => 'nullable|string|max:500',
            'question_en' => 'nullable|string|max:500',
            'corrected_answer_bn' => 'nullable|string',
            'corrected_answer_en' => 'nullable|string',
            'notes' => 'nullable|string|max:500',
            'priority' => 'nullable|integer|min:0|max:9999',
            'is_active' => 'nullable|boolean',
            'is_approved' => 'nullable|boolean',
        ]) + [
            'corrected_answer' => $request->input('corrected_answer_en') ?: $request->input('corrected_answer_bn'),
            'priority' => (int) ($request->input('priority') ?? 100),
            'is_active' => $request->boolean('is_active'),
            'is_approved' => $request->boolean('is_approved'),
            'version' => $updating ? (int) $request->input('version', 1) : 1,
        ];
    }

    protected function makeNormalizedKey(string $value): string
    {
        $key = Str::slug(Str::lower(trim($value)), '-');

        return $key !== '' ? $key : 'entry-' . now()->timestamp;
    }

    protected function ensureUnique($query, string $column, string $value): void
    {
        if ($query->where($column, $value)->exists()) {
            throw ValidationException::withMessages([
                $column => [translate('Duplicate entry detected')],
            ]);
        }
    }

    protected function redirectToBoard(string $anchor = ''): RedirectResponse
    {
        $url = route('admin.business-settings.ai-chat-board');
        if ($anchor !== '') {
            $url .= '#' . $anchor;
        }

        return redirect()->to($url);
    }

    protected function hasTable(string $table): bool
    {
        return Schema::hasTable($table);
    }

    protected function hasColumn(string $table, string $column): bool
    {
        return Schema::hasTable($table) && Schema::hasColumn($table, $column);
    }

    protected function emptyPaginator(Request $request, string $pageName, int $perPage): LengthAwarePaginator
    {
        return new LengthAwarePaginator(
            [],
            0,
            $perPage,
            1,
            [
                'path' => $request->url(),
                'pageName' => $pageName,
            ]
        );
    }
}
