<?php

namespace App\Services;

use App\Models\Certificate;
use Illuminate\Support\Facades\DB;

class CertificateSerialGenerator
{
    /**
     * Certificate type prefixes
     */
    private static $TYPE_PREFIXES = [
        'quiz' => 'QZ',
        'course' => 'CO',
        'imtmontessori' => 'IM',
    ];

    /**
     * Generate a unique serial number for a certificate
     *
     * @param string $certificateType
     * @return string
     */
    public static function generate(string $certificateType): string
    {
        // Get the prefix for the certificate type
        $prefix = self::$TYPE_PREFIXES[$certificateType] ?? 'UN';
        
        // Get current year
        $year = date('Y');
        
        // Get the next sequence number for this type and year
        $sequence = self::getNextSequence($certificateType, $year);
        
        // Format: PREFIX-YEAR-SEQUENCE (6 digits)
        return sprintf('%s-%s-%06d', $prefix, $year, $sequence);
    }

    /**
     * Get the next sequence number for a certificate type and year
     *
     * @param string $certificateType
     * @param string $year
     * @return int
     */
    private static function getNextSequence(string $certificateType, string $year): int
    {
        $prefix = self::$TYPE_PREFIXES[$certificateType] ?? 'UN';
        $pattern = $prefix . '-' . $year . '-%';

        // Use database transaction to ensure uniqueness
        return DB::transaction(function () use ($pattern, $certificateType, $year) {
            // Lock the table to prevent race conditions
            DB::statement('LOCK TABLES certificates WRITE');

            try {
                // Get the highest sequence number for this type and year
                $lastCertificate = Certificate::where('serial_number', 'LIKE', $pattern)
                    ->orderBy('serial_number', 'desc')
                    ->lockForUpdate()
                    ->first();

                if ($lastCertificate) {
                    // Extract sequence number from serial (e.g., "QZ-2024-000005" -> 5)
                    $lastSerial = $lastCertificate->serial_number;
                    $lastSequence = (int) substr($lastSerial, -6);
                    return $lastSequence + 1;
                } else {
                    // First certificate of this type for this year
                    return 1;
                }
            } finally {
                DB::statement('UNLOCK TABLES');
            }
        });
    }

    /**
     * Check if a serial number is valid and unique
     *
     * @param string $serialNumber
     * @return bool
     */
    public static function isValidAndUnique(string $serialNumber): bool
    {
        // Check format: XX-YYYY-NNNNNN
        if (!preg_match('/^[A-Z]{2}-\d{4}-\d{6}$/', $serialNumber)) {
            return false;
        }

        // Check if it already exists
        return !Certificate::where('serial_number', $serialNumber)->exists();
    }

    /**
     * Get certificate type from serial number
     *
     * @param string $serialNumber
     * @return string|null
     */
    public static function getTypeFromSerial(string $serialNumber): ?string
    {
        $prefix = substr($serialNumber, 0, 2);
        
        foreach (self::$TYPE_PREFIXES as $type => $typePrefix) {
            if ($typePrefix === $prefix) {
                return $type;
            }
        }
        
        return null;
    }


} 