<?php

namespace App\Models;

use CodeIgniter\Model;

class OrderModel extends Model
{
    protected $table            = 'orders';
    protected $primaryKey       = 'id_order';
    protected $useAutoIncrement = true;
    protected $returnType       = 'array';
    protected $useSoftDeletes   = false;
    protected $protectFields    = true;
    protected $allowedFields    = [
        'order_number',
        'customer_name',
        'customer_phone',
        'customer_email',
        'order_type',
        'total',
        'grand_total',
        'paid_amount',
        'remaining_amount',
        'payment_method',
        'payment_status',
        'production_status',
        'order_status',
        'notes',
        'target_date',
        'created_at',
        'updated_at'
    ];

    // Validation Rules
    protected $validationRules = [
        'customer_name' => 'required|min_length[3]',
        'total'         => 'required|decimal',
        'order_type'    => 'required|in_list[ready,po]'
    ];

    protected $validationMessages = [
        'customer_name' => [
            'required'   => 'Nama customer wajib diisi.',
            'min_length' => 'Nama customer minimal 3 karakter.'
        ],
        'total' => [
            'required' => 'Total order wajib diisi.',
            'decimal'  => 'Total order tidak valid.'
        ]
    ];

    // Timestamp configuration
    protected $useTimestamps = true;
    protected $dateFormat    = 'datetime';
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';

    /**
     * Generate Nomor Order Otomatis (Format: ORD-YYYYMMDD-0001)
     */
    public function generateOrderNumber(): string
    {
        $prefix = 'ORD-' . date('Ymd') . '-';
        $last   = $this->like('order_number', $prefix, 'after')
                       ->orderBy('id_order', 'DESC')
                       ->first();

        if (!$last) {
            return $prefix . '0001';
        }

        $lastNumber = (int) substr($last['order_number'], -4);
        return $prefix . str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
    }

    /**
     * Hitung Sisa Pembayaran
     */
    public function calculateRemaining(float $total, float $paid): float
    {
        return max(0, $total - $paid);
    }

    /**
     * Tentukan Status Pembayaran
     */
    public function calculatePaymentStatus(float $total, float $paid): string
    {
        if ($paid <= 0) {
            return 'unpaid';
        }
        if ($paid >= $total) {
            return 'paid';
        }
        return 'partial';
    }

    /**
     * Normalisasi status produksi agar konsisten antara admin dan owner
     */
    public function normalizeProductionStatus(string $status): string
    {
        $map = [
            'waiting'   => 'waiting',
            'antrian'   => 'waiting',
            'process'   => 'process',
            'progress'  => 'process',
            'produksi'  => 'process',
            'completed' => 'completed',
            'complete'  => 'completed',
            'selesai'   => 'completed',
            'cancelled' => 'cancelled',
            'cancel'    => 'cancelled',
        ];

        return $map[$status] ?? 'waiting';
    }

    /**
     * Order Hari Ini
     */
    public function today()
    {
        return $this->where('DATE(created_at)', date('Y-m-d'))->findAll();
    }

    /**
     * Total Sales Hari Ini
     */
    public function todaySales(): float
    {
        $row = $this->selectSum('paid_amount')
                    ->where('DATE(created_at)', date('Y-m-d'))
                    ->first();

        return (float) ($row['paid_amount'] ?? 0);
    }

    /**
     * Order Produksi / Antrian PO
     */
    public function productionQueue()
    {
        return $this->where('order_type', 'po')
                    ->whereNotIn('order_status', ['completed', 'cancelled'])
                    ->orderBy('target_date', 'ASC')
                    ->findAll();
    }

    /**
     * Outstanding Payment / Belum Lunas
     */
    public function outstanding()
    {
        return $this->where('payment_status !=', 'paid')->findAll();
    }

    /**
     * Update Pembayaran
     */
    public function updatePayment(int $id, float $paidAmount): bool
    {
        $order = $this->find($id);
        if (!$order) {
            return false;
        }

        $total       = (float) ($order['total'] ?? 0);
        $currentPaid = (float) ($order['paid_amount'] ?? 0);
        $paid        = min($total, $currentPaid + $paidAmount);
        $remaining   = $this->calculateRemaining($total, $paid);
        $status      = $this->calculatePaymentStatus($total, $paid);

        return $this->update($id, [
            'paid_amount'      => $paid,
            'remaining_amount' => $remaining,
            'payment_status'   => $status
        ]);
    }

    /**
     * Hitung total sales / omzet hari ini (Dashboard Support)
     */
    public function getTodaySales()
    {
        $today = date('Y-m-d');
        $row   = $this->selectSum('paid_amount')
                      ->where('DATE(created_at)', $today)
                      ->where('order_status !=', 'cancelled')
                      ->first();

        return (float) ($row['paid_amount'] ?? 0);
    }

    /**
     * Ringkasan status dan nominal pembayaran seluruh order yang tidak dibatalkan.
     *
     * Nilai piutang dihitung ulang dari total dikurangi nominal yang sudah
     * dibayar. Dengan begitu dashboard tetap akurat jika data sisa tagihan
     * lama belum tersinkronisasi.
     */
    public function getPaymentSummary(): array
    {
        $status    = "LOWER(COALESCE(payment_status, 'unpaid'))";
        $remaining = 'GREATEST(COALESCE(total, 0) - COALESCE(paid_amount, 0), 0)';

        $row = $this->db->table($this->table)
            ->select(implode(', ', [
                "COALESCE(SUM(CASE WHEN {$status} = 'paid' THEN 1 ELSE 0 END), 0) AS paid_orders",
                "COALESCE(SUM(CASE WHEN {$status} = 'partial' THEN 1 ELSE 0 END), 0) AS partial_orders",
                "COALESCE(SUM(CASE WHEN {$status} = 'unpaid' THEN 1 ELSE 0 END), 0) AS unpaid_orders",
                'COALESCE(SUM(COALESCE(paid_amount, 0)), 0) AS received_amount',
                "COALESCE(SUM(CASE WHEN {$status} = 'paid' THEN COALESCE(paid_amount, 0) ELSE 0 END), 0) AS settled_amount",
                "COALESCE(SUM(CASE WHEN {$status} = 'partial' THEN {$remaining} ELSE 0 END), 0) AS partial_outstanding_amount",
                "COALESCE(SUM(CASE WHEN {$status} = 'unpaid' THEN {$remaining} ELSE 0 END), 0) AS unpaid_amount",
                "COALESCE(SUM(CASE WHEN {$status} != 'paid' THEN {$remaining} ELSE 0 END), 0) AS outstanding_amount",
            ]), false)
            ->where('order_status !=', 'cancelled')
            ->get()
            ->getRowArray() ?? [];

        return [
            'paid_orders'               => (int) ($row['paid_orders'] ?? 0),
            'partial_orders'            => (int) ($row['partial_orders'] ?? 0),
            'unpaid_orders'             => (int) ($row['unpaid_orders'] ?? 0),
            'received_amount'           => (float) ($row['received_amount'] ?? 0),
            'settled_amount'            => (float) ($row['settled_amount'] ?? 0),
            'partial_outstanding_amount' => (float) ($row['partial_outstanding_amount'] ?? 0),
            'unpaid_amount'             => (float) ($row['unpaid_amount'] ?? 0),
            'outstanding_amount'        => (float) ($row['outstanding_amount'] ?? 0),
        ];
    }

    /**
     * Hitung total piutang (unpaid & partial).
     */
    public function getReceivable(): float
    {
        return $this->getPaymentSummary()['outstanding_amount'];
    }

    /**
     * Hitung total pesanan aktif
     */
    public function getActiveOrdersCount()
    {
        return $this->whereNotIn('order_status', ['completed', 'cancelled'])
                    ->countAllResults();
    }

    /**
     * Hitung status pembayaran spesifik
     */
    public function getPaymentStatusCount(string $status)
    {
        return $this->where('payment_status', $status)
                    ->where('order_status !=', 'cancelled')
                    ->countAllResults();
    }

    /**
     * Ambil daftar deadline terdekat
     */
    public function getUpcomingDeadlines(int $limit = 8)
    {
        $today = date('Y-m-d');
        return $this->db->table($this->table . ' o')
                    ->select('o.id_order, o.order_number, o.target_date, o.customer_name, SUM(oi.qty) as total_qty')
                    ->join('order_items oi', 'oi.id_order = o.id_order', 'left')
                    ->where('o.order_status !=', 'cancelled')
                    ->where('o.order_status !=', 'completed')
                    ->where('o.target_date >=', $today)
                    ->groupBy('o.id_order')
                    ->orderBy('o.target_date', 'ASC')
                    ->limit($limit)
                    ->get()->getResultArray();
    }
}
