<?php

namespace App\Support;

use Closure;

class FormTextRules
{
    /**
     * Reject values that are entirely digits (e.g. "12345").
     * Allows mixed text like "Laptop 15" or "Policy 2024".
     */
    public const NUMERIC_ONLY = '/^\d+$/';

    /**
     * Letters and digits only (no spaces or special characters).
     */
    public const ALPHANUMERIC = '/^[A-Za-z0-9]+$/';

    /**
     * @return list<string|Closure>
     */
    public static function notNumericOnly(bool $required = true, int $max = 191): array
    {
        $rules = $required ? ['required', 'string'] : ['nullable', 'string'];
        $rules[] = 'max:'.$max;
        $rules[] = 'not_regex:'.self::NUMERIC_ONLY;

        return $rules;
    }

    /**
     * Same as notNumericOnly, but strips HTML tags before the numeric-only check (rich text).
     *
     * @return list<string|Closure>
     */
    public static function notNumericOnlyHtml(bool $required = false, int $max = 50000): array
    {
        $rules = $required ? ['required', 'string'] : ['nullable', 'string'];
        $rules[] = 'max:'.$max;
        $rules[] = function (string $attribute, mixed $value, Closure $fail): void {
            if ($value === null || $value === '') {
                return;
            }

            $text = trim(html_entity_decode(strip_tags((string) $value), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
            if ($text === '') {
                return;
            }

            if (preg_match(self::NUMERIC_ONLY, $text) === 1) {
                $fail('The '.$attribute.' cannot be numbers only.');
            }
        };

        return $rules;
    }

    /**
     * @return list<string>
     */
    public static function alphanumericOptional(int $max = 100): array
    {
        return ['nullable', 'string', 'max:'.$max, 'regex:'.self::ALPHANUMERIC];
    }

    /**
     * @return array<string, string>
     */
    public static function messages(): array
    {
        return [
            'name.not_regex' => 'The name cannot be numbers only.',
            'title.not_regex' => 'The title cannot be numbers only.',
            'team.not_regex' => 'The team cannot be numbers only.',
            'subject.not_regex' => 'The subject cannot be numbers only.',
            'description.not_regex' => 'The description cannot be numbers only.',
            'content.not_regex' => 'The content cannot be numbers only.',
            'body.not_regex' => 'The body cannot be numbers only.',
            'reason.not_regex' => 'The reason cannot be numbers only.',
            'notes.not_regex' => 'The notes cannot be numbers only.',
            'reason_type.not_regex' => 'The reason type cannot be numbers only.',
            'location.not_regex' => 'The location cannot be numbers only.',
            'address.not_regex' => 'The address cannot be numbers only.',
            'terminal_alias.not_regex' => 'The terminal alias cannot be numbers only.',
            'serial_number.regex' => 'The serial number may only contain letters and numbers.',
            'weekoff_rule_id.required' => 'Please select a weekoff rule.',
            'user_ids.required' => 'Please select at least one employee.',
            'user_id.required' => 'Please select an owner.',
            'fields.*.label.not_regex' => 'Field labels cannot be numbers only.',
            'components.*.name.not_regex' => 'Component names cannot be numbers only.',
            'asset_type_id.required' => 'Please select an asset type.',
            'department_id.required' => 'Please select a department.',
            'job_posting_id.required' => 'Please select a job posting.',
            'resume.required' => 'Please upload a resume.',
            'target.required' => 'Please enter a target.',
            'assigned_to.required_if' => 'Please select who the asset is assigned to.',
            'purchase_date.before_or_equal' => 'The purchase date cannot be in the future.',
            'issued_on.before_or_equal' => 'The issued date cannot be in the future.',
            'appreciation_date.before_or_equal' => 'The appreciation date cannot be in the future.',
            'half_leave.required_if' => 'Please select a half-day slot.',
            'last_working_date.after_or_equal' => 'The last working date must be on or after the resignation date.',
            'applied_at.after_or_equal' => 'The applied date must be on or after the job posting date.',
            'clock_out_time.different' => 'Clock out time must be different from clock in time.',
        ];
    }
}
