<?php

namespace App\Livewire\Admin\Pesanan;

use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Enums\PaymentStatus;
use App\Models\Order;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;

#[Layout('layouts.admin')]
#[Title('Detail Pesanan')]
class Show extends Component
{
    public Order $order;

    public bool $showStatusModal = false;
    public string $newStatus     = '';
    public string $statusNote    = '';

    public bool $showCancelModal = false;
    public string $cancelReason  = '';

    public function mount(int $id): void
    {
        $this->order = Order::with([
            'items.product',
            'payment.verifiedBy',
            'deliveryArea',
            'assignedAdmin',
            'voucher',
            'user',
            'guestCustomer',
        ])->findOrFail($id);
    }

    public function openStatusModal(): void
    {
        $this->newStatus       = '';
        $this->statusNote      = '';
        $this->showStatusModal = true;
    }

    public function updateStatus(): void
    {
        abort_unless(Auth::user()->can('order.update-status'), 403);

        $this->validate([
            'newStatus' => ['required', 'string'],
        ]);

        $current = $this->order->status;
        $target  = OrderStatus::from($this->newStatus);

        if (! $current->canTransitionTo($target)) {
            $this->addError('newStatus', 'Transisi status dari "' . $current->label() . '" ke "' . $target->label() . '" tidak diizinkan.');
            return;
        }

        // BFS v1.1 Phase B — Rule-1: blok perubahan ke 'paid' dari Menu Pesanan.
        // Status paid hanya boleh berasal dari verifyPayment() di Menu Pembayaran.
        if ($target === OrderStatus::Paid) {
            $this->addError('newStatus', 'Status "Sudah Dibayar" hanya dapat diberikan melalui proses verifikasi pembayaran di Menu Pembayaran.');
            return;
        }

        // BFS v1.1 Phase B — Rule-2 & Rule-3: validasi status payment sebelum operasional.
        // Khusus untuk target processing/delivering/completed pada order NON-COD.
        // COD dikecualikan karena pembayaran diterima saat serah terima (BFS v1.1 Revisi R-1).
        $operationalStatuses = [OrderStatus::Processing, OrderStatus::Delivering, OrderStatus::Completed];
        if (in_array($target, $operationalStatuses) && $this->order->payment_method !== PaymentMethod::Cod) {
            $payment = $this->order->payment; // sudah di-eager-load di mount(), tidak ada query baru

            if (! $payment || $payment->status === PaymentStatus::Pending) {
                $this->addError('newStatus', 'Pesanan tidak dapat diproses karena pembayaran belum diverifikasi.');
                return;
            }

            if ($payment->status === PaymentStatus::Rejected) {
                $this->addError('newStatus', 'Pesanan tidak dapat diproses karena pembayaran telah ditolak. Minta customer mengupload ulang bukti pembayaran.');
                return;
            }
        }

        $this->order->update([
            'status'      => $target->value,
            'admin_notes' => $this->statusNote
                ? trim(($this->order->admin_notes ? $this->order->admin_notes . "\n" : '') . $this->statusNote)
                : $this->order->admin_notes,
        ]);

        $this->order->refresh();
        $this->showStatusModal = false;
        $this->dispatch('refresh-admin-badges');
        $this->dispatch('notify', type: 'success', message: 'Status pesanan berhasil diubah menjadi "' . $target->label() . '".');
    }

    public function openCancelModal(): void
    {
        $this->cancelReason    = '';
        $this->showCancelModal = true;
    }

    public function cancelOrder(): void
    {
        abort_unless(Auth::user()->can('order.cancel'), 403);

        if (! $this->order->isCancellable()) {
            $this->addError('cancelReason', 'Pesanan dengan status "' . $this->order->status->label() . '" tidak dapat dibatalkan.');
            return;
        }

        $this->order->update([
            'status'      => OrderStatus::Cancelled->value,
            'admin_notes' => trim(($this->order->admin_notes ? $this->order->admin_notes . "\n" : '') . 'Dibatalkan: ' . $this->cancelReason),
        ]);

        $this->order->refresh();
        $this->showCancelModal = false;
        $this->dispatch('refresh-admin-badges');
        $this->dispatch('notify', type: 'success', message: 'Pesanan berhasil dibatalkan.');
    }

    public function render()
    {
        // ── Ambil semua activity log untuk order ini ────────────────────────
        // Dipakai untuk mengambil TIMESTAMP per status, bukan untuk urutan tampil.
        $logs = Activity::query()
            ->where('subject_type', Order::class)
            ->where('subject_id', $this->order->id)
            ->where('log_name', 'order')
            ->with('causer')
            ->oldest()
            ->get();

        // Buat index: status_value => log pertama yang mencatat status itu
        // Dipakai untuk mengambil timestamp + causer per step.
        $logByStatus = [];
        foreach ($logs as $log) {
            $statusValue = $log->properties['attributes']['status'] ?? null;
            if ($statusValue && ! isset($logByStatus[$statusValue])) {
                $logByStatus[$statusValue] = $log;
            }
        }

        // ── Urutan tetap alur bisnis ────────────────────────────────────────
        // Instruksi: urutan TIDAK BOLEH mengikuti hasil query database.
        // Cancelled ditampilkan terpisah di akhir hanya jika memang terjadi.
        $statusOrder = [
            OrderStatus::Pending,
            OrderStatus::Paid,
            OrderStatus::Processing,
            OrderStatus::Delivering,
            OrderStatus::Completed,
        ];

        $currentStatus = $this->order->status;
        $isCancelled   = $currentStatus === OrderStatus::Cancelled;

        // ── Bangun steps timeline ───────────────────────────────────────────
        // Setiap step: status, label, sudah_lewat (done), aktif, timestamp, causer
        $timeline = [];

        // Step 1: Pesanan Dibuat — selalu done, timestamp dari created_at order
        $timeline[] = [
            'label'     => 'Pesanan Dibuat',
            'done'      => true,
            'active'    => false,
            'timestamp' => $this->order->created_at,
            'causer'    => null,
        ];

        foreach ($statusOrder as $status) {
            $log        = $logByStatus[$status->value] ?? null;
            $isActive   = $currentStatus === $status;
            $isDone     = $this->isStatusReached($status, $currentStatus, $isCancelled);

            $timeline[] = [
                'label'     => $status->label(),
                'done'      => $isDone && ! $isActive,
                'active'    => $isActive,
                'timestamp' => $log?->created_at,
                'causer'    => $log?->causer,
            ];
        }

        // Tambahkan "Dibatalkan" di akhir hanya jika status order memang Cancelled
        if ($isCancelled) {
            $log = $logByStatus[OrderStatus::Cancelled->value] ?? null;
            $timeline[] = [
                'label'     => OrderStatus::Cancelled->label(),
                'done'      => false,
                'active'    => true,
                'timestamp' => $log?->created_at,
                'causer'    => $log?->causer,
            ];
        }

        return view('livewire.admin.pesanan.show', compact('timeline'));
    }

    /**
     * Tentukan apakah suatu status sudah dilewati berdasarkan status order saat ini.
     * Menggunakan urutan enum yang sudah didefinisikan di allowedTransitions().
     */
    private function isStatusReached(
        OrderStatus $check,
        OrderStatus $current,
        bool $isCancelled
    ): bool {
        if ($isCancelled) {
            // Kalau dibatalkan, hanya status sebelum cancelled yang dianggap done
            $reachable = [OrderStatus::Pending, OrderStatus::Paid];
            return in_array($check, $reachable);
        }

        $order = [
            OrderStatus::Pending,
            OrderStatus::Paid,
            OrderStatus::Processing,
            OrderStatus::Delivering,
            OrderStatus::Completed,
        ];

        $checkIdx   = array_search($check,   $order);
        $currentIdx = array_search($current, $order);

        return $checkIdx !== false && $currentIdx !== false && $checkIdx <= $currentIdx;
    }
}
