<?php

namespace App\Actions\Voucher;

use App\Models\User;
use App\Models\Voucher;
use Carbon\Carbon;

final class ValidateVoucherAction
{
    /**
     * @return array{valid: bool, message: string, voucher: ?Voucher}
     */
    public function handle(string $code, User $user, ?string $ip = null): array
    {
        $voucher = Voucher::byCode($code)->first();

        if (! $voucher) {
            return ['valid' => false, 'message' => 'Invalid voucher code', 'voucher' => null];
        }

        if (! $voucher->isValid()) {
            $message = match (true) {
                $voucher->is_used => 'This voucher has already been used',
                $voucher->usage_count >= $voucher->usage_limit => 'This voucher has reached its usage limit',
                $voucher->expire_date && $voucher->expire_date < now() => 'This voucher has expired',
                default => 'Voucher is not valid',
            };

            return ['valid' => false, 'message' => $message, 'voucher' => null];
        }

        if ($registrationMessage = $this->getRegistrationRestrictionMessage($voucher, $user)) {
            return ['valid' => false, 'message' => $registrationMessage, 'voucher' => null];
        }

        if ($ip && $voucher->is_redeemed_by_ip && $voucher->redeemed_ip && $voucher->redeemed_ip === $ip) {
            return ['valid' => false, 'message' => 'This voucher can only be redeemed once per IP address', 'voucher' => null];
        }

        return ['valid' => true, 'message' => 'Voucher is valid', 'voucher' => $voucher];
    }

    private function getRegistrationRestrictionMessage(Voucher $voucher, User $user): ?string
    {
        $eligibleDate = $voucher->getAttributes()['eligible_register_date'] ?? null;

        if ($eligibleDate === null) {
            return null;
        }

        if (is_string($eligibleDate)) {
            $eligibleDate = trim($eligibleDate);
            if ($eligibleDate === '' || $eligibleDate === '0000-00-00') {
                return null;
            }
            $eligibleDate = Carbon::parse($eligibleDate)->toDateString();
        } else {
            $eligibleDate = $eligibleDate->toDateString();
        }

        if (! $user->creatime) {
            return 'This voucher has an account registration date requirement that is not met.';
        }

        $userRegisterDate = Carbon::parse($user->creatime)->toDateString();

        if ($userRegisterDate >= $eligibleDate) {
            return null;
        }

        return "This voucher is only for accounts registered on or after {$eligibleDate}.";
    }
}
