<?php
namespace App\Models;

use CodeIgniter\Model;

class DiscountVoucherModel extends Model
{
    protected $table      = 'discount_vouchers';
    protected $primaryKey = 'id';

    protected $allowedFields = [
        'code',
        'discount_type',
        'discount_value',
        'max_uses',
        'times_used',
        'valid_from',
        'valid_until',
        'semester',
        'school_year',
        'is_active',
        'description',      // <-- NEW
        'created_at',
        'updated_at',
    ];

    // Timestamps managed by CI
    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';

    // Basic validation
    protected $validationRules = [
        'code'           => 'required|alpha_numeric_punct|max_length[50]|is_unique[discount_vouchers.code,id,{id}]',
        'discount_type'  => 'required|in_list[percent,fixed]',
        'discount_value' => 'required|numeric|greater_than_equal_to[0]',
        'max_uses'       => 'permit_empty|is_natural',
        'valid_from'     => 'permit_empty|valid_date[Y-m-d]',
        'valid_until'    => 'permit_empty|valid_date[Y-m-d]',
        'is_active'      => 'in_list[0,1]',
        'description'    => 'permit_empty|string|max_length[1000]', // <-- NEW
    ];

    protected $validationMessages = [
        'code' => [
            'is_unique' => 'The voucher code must be unique.',
        ],
        'discount_type' => [
            'in_list' => 'The discount type must be either "percent" or "fixed".',
        ],
    ];

    // Normalize inputs before save
    protected $beforeInsert = ['normalizeFields', 'validateDatesOrder'];
    protected $beforeUpdate = ['normalizeFields', 'validateDatesOrder'];

    protected function normalizeFields(array $data): array
    {
        if (!isset($data['data'])) return $data;

        // Normalize code: keep A-Z, 0-9 and dashes, uppercased
        if (array_key_exists('code', $data['data'])) {
            $raw               = (string) $data['data']['code'];
            $normalized        = strtoupper(preg_replace('/[^A-Z0-9\-]/i', '', trim($raw)));
            $data['data']['code'] = $normalized;
        }

        // Empty strings -> NULL for dates & max_uses
        foreach (['valid_from', 'valid_until'] as $f) {
            if (array_key_exists($f, $data['data'])) {
                $v = trim((string) $data['data'][$f]);
                $data['data'][$f] = ($v === '') ? null : $v;
            }
        }
        if (array_key_exists('max_uses', $data['data'])) {
            $v = $data['data']['max_uses'];
            $data['data']['max_uses'] = ($v === '' || $v === null) ? null : max(0, (int) $v);
        }

        // Coerce booleans
        if (array_key_exists('is_active', $data['data'])) {
            $data['data']['is_active'] = (int) !!$data['data']['is_active'];
        }

        return $data;
    }

    protected function validateDatesOrder(array $data): array
    {
        if (!isset($data['data'])) return $data;

        $from = $data['data']['valid_from'] ?? null;
        $until = $data['data']['valid_until'] ?? null;

        if ($from && $until && $from > $until) {
            // Inject a model error; save() will fail and return errors()
            $this->validator->setError('valid_until', 'Valid Until must be the same as or after Valid From.');
        }
        return $data;
    }

    /**
     * Find a valid voucher for a student (not expired, active, under max uses, and not used by the student).
     */
    public function findValidVoucher(string $code, int $studentId)
    {
        $code = strtoupper(preg_replace('/\s+/', '', trim($code))); // simple normalize to match stored code

        $builder = $this->db->table('discount_vouchers v')
            ->select('v.*')
            // Left join usages for this student only
            ->join('discount_usages u', 'u.voucher_id = v.id AND u.student_id = ' . (int) $studentId, 'left')
            ->where('v.code', $code)
            ->where('v.is_active', 1)
            // valid_from is null or <= today
            ->groupStart()
                ->where('v.valid_from IS NULL', null, false)
                ->orWhere('v.valid_from <=', date('Y-m-d'))
            ->groupEnd()
            // valid_until is null or >= today
            ->groupStart()
                ->where('v.valid_until IS NULL', null, false)
                ->orWhere('v.valid_until >=', date('Y-m-d'))
            ->groupEnd()
            // max_uses is null or times_used < max_uses  (use raw to compare two columns)
            ->groupStart()
                ->where('v.max_uses IS NULL', null, false)
                ->orWhere('v.times_used < v.max_uses', null, false)
            ->groupEnd()
            // Not previously used by this student (no usage row)
            ->where('u.id IS NULL', null, false);

        return $builder->get()->getRow();
    }
}
