<?php

namespace App\Livewire;

use App\Services\ChatbotService;
use App\Services\GeminiChatbotService;
use Livewire\Component;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ChatBot extends Component
{
    // ── Panel state ───────────────────────────────────────────────────────────
    public bool   $isOpen = false;

    /**
     * 'select'   → mode-picker screen shown first
     * 'basic'    → structured query UI (production or invoice report)
     * 'advanced' → free-text natural-language UI (Gemini-powered)
     */
    public string $mode = 'select';

    // ── Basic mode — shared ───────────────────────────────────────────────────

    /**
     * Which report the user picked inside basic mode.
     * ''               → report-type picker shown
     * 'production'     → production form
     * 'invoice'        → invoice type-lookup form
     * 'invoice_status' → invoice scan-status form
     */
    public string $reportType = '';

    public array $plants = [];

    // ── Basic mode — Production report ───────────────────────────────────────
    public string  $result           = '';
    public bool    $hasResult        = false;

    public ?int    $selectedPlantId  = null;
    public ?int    $selectedLineId   = null;
    public string  $dateFrom         = '';
    public string  $dateTo           = '';
    public array   $lines            = [];

    // ── Basic mode — Invoice report (type lookup) ─────────────────────────────
    public ?int    $invoicePlantId   = null;
    public string  $invoiceItemCode  = '';
    public string  $invoiceResult    = '';
    public bool    $hasInvoiceResult = false;

    // ── Basic mode — Invoice status (scan status) ─────────────────────────────
    public string  $invoiceNumber          = '';
    public string  $invoiceStatusResult    = '';   // kept for simple error strings
    public bool    $hasInvoiceStatusResult = false;

    /**
     * Structured result from ChatbotService::getInvoiceData().
     * Shape: type, message, invoice_number, total, scanned, not_scanned, unscanned_serials[]
     */
    public array   $invoiceStatusData   = [];

    /** Controls whether all unscanned serials are shown (vs the first 10). */
    public bool    $showAllUnscanned    = false;

    // ── Advanced mode ─────────────────────────────────────────────────────────
    public string $advancedQuestion   = '';
    public string $advancedResult     = '';
    public bool   $hasAdvancedResult  = false;
    public bool   $isAdvancedLoading  = false;

    /**
     * Conversation history shown in advanced mode.
     * Each entry: ['role' => 'user'|'assistant', 'content' => '…']
     *
     * The full history is passed to GeminiChatbotService on every turn so
     * Gemini can resolve follow-up messages (e.g. answering a clarification
     * question) in context.
     */
    public array $chatHistory = [];

    // ─────────────────────────────────────────────────────────────────────────

    public function mount(): void
    {
        $this->plants = DB::table('plants')
            ->whereNull('deleted_at')
            ->orderBy('name')
            ->get(['id', 'name'])
            ->toArray();

        $this->dateFrom = now()->startOfMonth()->format('Y-m-d');
        $this->dateTo   = now()->format('Y-m-d');
    }

    // ── Mode switching ────────────────────────────────────────────────────────

    public function setMode(string $mode): void
    {
        $this->mode = $mode;
    }

    public function setReportType(string $type): void
    {
        $this->reportType = $type;

        // Clear previous results when switching report type
        $this->result                 = '';
        $this->hasResult              = false;
        $this->invoiceResult          = '';
        $this->hasInvoiceResult       = false;
        $this->invoiceStatusResult    = '';
        $this->hasInvoiceStatusResult = false;
        $this->invoiceStatusData      = [];
        $this->showAllUnscanned       = false;
    }

    // ── Basic mode — Production helpers ──────────────────────────────────────

    public function updatedSelectedPlantId(): void
    {
        $this->selectedLineId = null;
        $this->lines          = [];
        $this->result         = '';
        $this->hasResult      = false;

        if ($this->selectedPlantId) {
            $this->lines = DB::table('lines')
                ->whereNull('deleted_at')
                ->where('plant_id', $this->selectedPlantId)
                ->orderBy('name')
                ->get(['id', 'name'])
                ->toArray();
        }
    }

    public function updatedSelectedLineId(): void
    {
        $this->result    = '';
        $this->hasResult = false;
    }

    public function fetchProduction(): void
    {
        if (! $this->selectedPlantId) {
            $this->result    = 'Please select a plant.';
            $this->hasResult = true;
            return;
        }

        $query = DB::table('production_quantities')
            ->whereNull('deleted_at')
            ->where('plant_id', $this->selectedPlantId)
            ->whereDate('created_at', '>=', $this->dateFrom)
            ->whereDate('created_at', '<=', $this->dateTo);

        if ($this->selectedLineId) {
            $query->where('line_id', $this->selectedLineId);
        }

        $count = $query->count();

        $plantName = collect($this->plants)
            ->firstWhere('id', $this->selectedPlantId)?->name ?? 'Unknown Plant';

        $lineName = $this->selectedLineId
            ? (collect($this->lines)->firstWhere('id', $this->selectedLineId)?->name ?? 'Unknown Line')
            : 'All Lines';

        $from = \Carbon\Carbon::parse($this->dateFrom)->format('d M Y');
        $to   = \Carbon\Carbon::parse($this->dateTo)->format('d M Y');

        $this->result    = "Production count for {$plantName} / {$lineName} from {$from} to {$to}: {$count} records.";
        $this->hasResult = true;
    }

    // ── Basic mode — Invoice report (type lookup) ─────────────────────────────

    public function updatedInvoicePlantId(): void
    {
        $this->invoiceResult    = '';
        $this->hasInvoiceResult = false;
    }

    public function updatedInvoiceItemCode(): void
    {
        $this->invoiceResult    = '';
        $this->hasInvoiceResult = false;
    }

    public function fetchInvoiceReport(): void
    {
        if (! $this->invoicePlantId) {
            $this->invoiceResult    = 'Please select a plant.';
            $this->hasInvoiceResult = true;
            return;
        }

        $itemCode = trim($this->invoiceItemCode);

        if ($itemCode === '') {
            $this->invoiceResult    = 'Please enter an item code.';
            $this->hasInvoiceResult = true;
            return;
        }

        $plantName = collect($this->plants)
            ->firstWhere('id', $this->invoicePlantId)?->name ?? 'Unknown Plant';

        try {
            $rows = DB::select("
                WITH plant_item AS (
                    SELECT ? AS user_plant,
                           ? AS user_item_code
                ),
                t1 AS (
                    SELECT
                        plants.id   AS plant_id,
                        plants.name AS plant_name,
                        ARRAY_AGG(items.code) AS item_codes
                    FROM plants
                    LEFT JOIN items ON plants.id = items.plant_id
                    GROUP BY plants.id, plants.name
                ),
                t2 AS (
                    SELECT
                        t1.plant_id,
                        t1.plant_name,
                        CASE
                            WHEN plant_item.user_item_code = ANY(t1.item_codes) THEN 1
                            ELSE 0
                        END AS exists_flag
                    FROM t1
                    CROSS JOIN plant_item
                    WHERE t1.plant_name = plant_item.user_plant
                ),
                t3 AS (
                    SELECT t2.plant_id, t2.plant_name, t2.exists_flag,
                           plant_item.user_item_code
                    FROM t2
                    LEFT JOIN plant_item ON plant_item.user_plant = t2.plant_name
                ),
                t4 AS (
                    SELECT items.id AS item_id,
                           t3.plant_id, t3.plant_name, t3.exists_flag, t3.user_item_code
                    FROM t3
                    LEFT JOIN items
                        ON t3.plant_id = items.plant_id
                       AND t3.user_item_code = items.code
                )
                SELECT
                    t4.item_id,
                    t4.plant_id,
                    t4.plant_name,
                    t4.exists_flag,
                    t4.user_item_code,
                    COALESCE(sticker_masters.material_type, 0) AS material_type,
                    CASE
                        WHEN sticker_masters.item_id IS NULL
                            THEN 'no match found'
                        WHEN COALESCE(sticker_masters.material_type, 0) = 0
                            THEN 'serial invoice'
                        ELSE 'material invoice'
                    END AS invoice_description
                FROM t4
                LEFT JOIN sticker_masters
                    ON sticker_masters.plant_id = t4.plant_id
                   AND sticker_masters.item_id  = t4.item_id
            ", [$plantName, $itemCode]);

        } catch (\Exception $e) {
            Log::error('ChatBot: invoice report query failed', [
                'plant'     => $plantName,
                'item_code' => $itemCode,
                'error'     => $e->getMessage(),
            ]);

            $this->invoiceResult    = "Sorry, I couldn't fetch data. Please try again or contact support.";
            $this->hasInvoiceResult = true;
            return;
        }

        if (empty($rows)) {
            $this->invoiceResult    = "No data found for plant \"{$plantName}\". Please verify the plant selection.";
            $this->hasInvoiceResult = true;
            return;
        }

        $row = $rows[0];

        if ((int) $row->exists_flag === 0) {
            $this->invoiceResult = 'Provided item code does not exist in the item table.';
        } else {
            switch ($row->invoice_description) {
                case 'no match found':
                    $this->invoiceResult = "Item not found in sticker master for the plant {$row->plant_name}.";
                    break;
                case 'serial invoice':
                    $this->invoiceResult = 'It is a serial invoice item.';
                    break;
                case 'material invoice':
                    $this->invoiceResult = 'It is a material invoice item.';
                    break;
                default:
                    $this->invoiceResult = 'Unexpected result. Please contact support.';
            }
        }

        $this->hasInvoiceResult = true;
    }

    // ── Basic mode — Invoice status (scan status) ─────────────────────────────

    public function updatedInvoiceNumber(): void
    {
        $this->invoiceStatusResult    = '';
        $this->hasInvoiceStatusResult = false;
        $this->invoiceStatusData      = [];
        $this->showAllUnscanned       = false;
    }

    /**
     * Looks up how many serials within an invoice have been scanned / not scanned.
     * Stores structured data in $invoiceStatusData so the blade can render
     * a "show more" serial-number list without dumping 70+ serials in one blob.
     */
    public function fetchInvoiceStatus(): void
    {
        $invoiceNumber = trim(preg_replace('/\s+/', '', $this->invoiceNumber));

        if (empty($invoiceNumber)) {
            $this->invoiceStatusResult    = 'Please enter a valid invoice number.';
            $this->invoiceStatusData      = [];
            $this->showAllUnscanned       = false;
            $this->hasInvoiceStatusResult = true;
            return;
        }

        try {
            /** @var \App\Services\ChatbotService $service */
            $service = app(\App\Services\ChatbotService::class);
            $data    = $service->getInvoiceData($invoiceNumber);
        } catch (\Throwable $e) {
            Log::error('ChatBot: invoice status fetch failed', [
                'invoice' => $invoiceNumber,
                'error'   => $e->getMessage(),
            ]);
            $data = [
                'type'              => 'error',
                'message'           => "Sorry, I couldn't fetch data for invoice {$invoiceNumber}. "
                                     . 'Please try again or contact support.',
                'invoice_number'    => $invoiceNumber,
                'total'             => 0,
                'scanned'           => 0,
                'not_scanned'       => 0,
                'unscanned_serials' => [],
            ];
        }

        $this->invoiceStatusData      = $data;
        $this->invoiceStatusResult    = $data['message'];  // fallback plain-text copy
        $this->showAllUnscanned       = false;
        $this->hasInvoiceStatusResult = true;
    }

    /**
     * Toggles the "show all / show less" state for unscanned serial numbers
     * in the Basic → Invoice Status result card.
     */
    public function toggleShowAllUnscanned(): void
    {
        $this->showAllUnscanned = ! $this->showAllUnscanned;
    }

    // ── Advanced mode (Gemini-powered) ────────────────────────────────────────

    /**
     * Handles a free-text user message in advanced mode.
     *
     * Steps:
     *   1. Appends the user message to chatHistory immediately (UI feedback).
     *   2. Calls GeminiChatbotService with the full prior history for context.
     *   3. Gemini classifies the intent, extracts params, and either:
     *        a) runs the appropriate DB query and returns the result, or
     *        b) returns a clarification question if intent is ambiguous.
     *   4. Appends the assistant reply to chatHistory.
     */
    public function askAdvanced(): void
    {
        $question = trim($this->advancedQuestion);

        if (empty($question)) {
            return;
        }

        // Show the user's message in the chat bubble immediately
        $this->chatHistory[] = [
            'role'    => 'user',
            'content' => $question,
        ];

        $this->advancedQuestion  = '';
        $this->isAdvancedLoading = true;

        try {
            /** @var GeminiChatbotService $gemini */
            $gemini = app(GeminiChatbotService::class);

            // Pass history *without* the turn we just appended — the new user
            // message is passed separately so Gemini sees it as the latest turn.
            $priorHistory = array_slice($this->chatHistory, 0, -1);
            $answer       = $gemini->processMessage($priorHistory, $question);

        } catch (\Throwable $e) {
            Log::error('ChatBot: advanced ask failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            $answer = 'Sorry, something went wrong. Please try again.';
        }

        $this->chatHistory[] = [
            'role'    => 'assistant',
            'content' => $answer,
        ];

        $this->isAdvancedLoading = false;
    }

    public function clearAdvancedChat(): void
    {
        $this->chatHistory       = [];
        $this->advancedQuestion  = '';
        $this->isAdvancedLoading = false;
    }

    // ── Panel controls ────────────────────────────────────────────────────────

    public function toggleChat(): void
    {
        $this->isOpen = ! $this->isOpen;
    }

    public function resetForm(): void
    {
        // Basic mode — shared
        $this->reportType = '';

        // Basic mode — production
        $this->selectedPlantId   = null;
        $this->selectedLineId    = null;
        $this->lines             = [];
        $this->result            = '';
        $this->hasResult         = false;
        $this->dateFrom          = now()->startOfMonth()->format('Y-m-d');
        $this->dateTo            = now()->format('Y-m-d');

        // Basic mode — invoice type lookup
        $this->invoicePlantId    = null;
        $this->invoiceItemCode   = '';
        $this->invoiceResult     = '';
        $this->hasInvoiceResult  = false;

        // Basic mode — invoice scan status
        $this->invoiceNumber          = '';
        $this->invoiceStatusResult    = '';
        $this->hasInvoiceStatusResult = false;
        $this->invoiceStatusData      = [];
        $this->showAllUnscanned       = false;

        // Advanced mode
        $this->clearAdvancedChat();

        // Go back to mode selector
        $this->mode = 'select';
    }

    public function render()
    {
        return view('livewire.chat-bot');
    }
}
