<?php

// source : https://knplabs.com/en/blog/how-to-map-a-php-enum-with-doctrine-in-a-symfony-project/

declare(strict_types=1);

namespace App\Doctrine\DBAL\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;

// class EnumTypeItem
// {
//     public string $value;
//     public string $label;
//     public function __serialize() : array
//     {
//         return [
//             "value" => $this->value,
//             "label" => $this->label,
//         ];
//     }

//     public function __unserialize(array $data) {
//         $this->value = $data["value"];
//         $this->label = $data["label"];
//     }
// }

abstract class EnumType extends Type
{
    /**
     * @return class-string 
     */

     /*
        The abstract getEnum method will have to be implemented and must return the FQCN of the according enum.
     */

     public abstract function getEnum(): string;

    /*
        The getSQLDeclaration method will be used by doctrine to generate the field signature during migrations / database updates and 
        is specific to the database platform that you use (here is an example for mysql). 
        The enum::cases() method is built-in in php and returns instances of enum values and therefore are not directly castable in 
        strings (or whatever type the enum values are). To get these raw values, enum have a public property called value. 
    */
    public function getSQLDeclaration(array $column, AbstractPlatform $platform = null): string 
    { 
        $enum = $this->getEnum();
        $cases = array_map(
            fn ($enumItem) => "'{$enumItem->value}'", 
            $enum::cases()
        );

        return sprintf('ENUM(%s)', implode(', ', $cases));
    }

    /*
        The requiresSQLCommentHint method is used to put a special comment on the column declaration and helps doctrine to make sure that the 
        field mapping is up-to-date. If you don't override this method to return true, doctrine will constantly try to update the column 
        definition each time you generate a migration for no reason.
    */
    public function requiresSQLCommentHint(AbstractPlatform $platform = null): bool
    {
        return true;
    }
    
    public function convertToPHPValue($value, AbstractPlatform $platform = null): mixed
    {
        $enumClass = $this->getEnum();
        
        return $enumClass::from($value);
    }

    public function convertToDatabaseValue($enum, AbstractPlatform $platform = null): mixed
    {
        try {
            return $enum->value;
        } catch (\Throwable $th) {
            // dump($enum);
            return $enum;
        }
    }
}