<?php

namespace App\Models;

use App\Models\BaseModel;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class DiscountVoucher extends BaseModel
{
    protected $table = 'discount_vouchers';

    // ✅ CI manages created_at / updated_at
    public $timestamps = true;

    protected $fillable = [
        'code',
        'discount_type',
        'description',
        'discount_value',
        'max_uses',
        'times_used',
        'valid_from',
        'valid_until',
        'is_active',
        'created_at',
        'updated_at',
        'school_year',
        'semester',
    ];

    protected $casts = [
        'discount_value' => 'decimal:2',
        'max_uses'       => 'integer',
        'times_used'     => 'integer',
        'is_active'      => 'boolean',
        'valid_from'     => 'date',
        'valid_until'    => 'date',
    ];

    /* =========================
     * Model hooks (CI beforeInsert/beforeUpdate equivalents)
     * ========================= */

    protected static function booted(): void
    {
        static::creating(function (self $m) {
            $m->normalizeFields();
            $m->validateDatesOrder(); // throws if invalid
        });

        static::updating(function (self $m) {
            $m->normalizeFields();
            $m->validateDatesOrder(); // throws if invalid
        });
    }

    private function normalizeFields(): void
    {
        // Normalize code: keep A-Z, 0-9 and dashes, uppercased
        if ($this->isDirty('code') && $this->code !== null) {
            $raw = (string) $this->code;
            $this->code = strtoupper(preg_replace('/[^A-Z0-9\-]/i', '', trim($raw)));
        }

        // Empty strings -> NULL for dates & max_uses
        foreach (['valid_from', 'valid_until'] as $f) {
            if ($this->isDirty($f)) {
                $v = $this->{$f};
                if (is_string($v)) {
                    $v = trim($v);
                    $this->{$f} = ($v === '') ? null : $v;
                }
            }
        }

        if ($this->isDirty('max_uses')) {
            $v = $this->max_uses;
            if ($v === '' || $v === null) {
                $this->max_uses = null;
            } else {
                $this->max_uses = max(0, (int) $v);
            }
        }

        if ($this->isDirty('is_active')) {
            $this->is_active = (bool) $this->is_active;
        }
    }

    private function validateDatesOrder(): void
    {
        if (!empty($this->valid_from) && !empty($this->valid_until)) {
            $from  = Carbon::parse($this->valid_from)->toDateString();
            $until = Carbon::parse($this->valid_until)->toDateString();
            if ($from > $until) {
                // In Laravel, prefer validating in FormRequest.
                // This keeps your CI behavior by failing the save.
                throw new \InvalidArgumentException('Valid Until must be the same as or after Valid From.');
            }
        }
    }

    /* =========================
     * Query helpers
     * ========================= */

    /**
     * Find a valid voucher for a student (not expired, active, under max uses, and not used by the student).
     *
     * NOTE: Your CI joins discount_usages on u.student_id. That requires discount_usages.student_id to exist.
     * If your discount_usages table does NOT have student_id (some of your other code uses parent_id),
     * switch the filter to parent_id instead.
     */
    public static function findValidVoucher(string $code, int $studentId): ?self
    {
        $code = strtoupper(preg_replace('/\s+/', '', trim($code)));
        $today = now()->toDateString();

        $q = static::query()
            ->from('discount_vouchers as v')
            ->select('v.*')
            // Left join usages for this student only
            ->leftJoin('discount_usages as u', function ($join) use ($studentId) {
                $join->on('u.voucher_id', '=', 'v.id')
                     ->where('u.student_id', '=', (int) $studentId);
            })
            ->where('v.code', $code)
            ->where('v.is_active', 1)
            // valid_from is null or <= today
            ->where(function ($w) use ($today) {
                $w->whereNull('v.valid_from')
                  ->orWhere('v.valid_from', '<=', $today);
            })
            // valid_until is null or >= today
            ->where(function ($w) use ($today) {
                $w->whereNull('v.valid_until')
                  ->orWhere('v.valid_until', '>=', $today);
            })
            // max_uses is null or times_used < max_uses
            ->where(function ($w) {
                $w->whereNull('v.max_uses')
                  ->orWhereColumn('v.times_used', '<', 'v.max_uses');
            })
            // Not previously used by this student (no usage row)
            ->whereNull('u.id')
            ->limit(1);

        return $q->first();
    }
}