<?php

declare(strict_types=1);

namespace App\Modules\Administration\Services;

use App\Modules\Administration\Repositories\DynamicFormFieldRepository;
use RuntimeException;

final class DynamicFormFieldService
{
    private const ALLOWED_TYPES = [
        'text',
        'textarea',
        'number',
        'date',
        'time',
        'select',
        'radio',
        'checkbox',
        'email',
        'phone',
        'file'
    ];

    private const ALLOWED_WIDTHS = [
        3,
        4,
        6,
        8,
        9,
        12
    ];

    public function __construct(
        private DynamicFormFieldRepository $fields
    ) {
    }

    public function byForm(
        int $formId
    ): array {
        return $this->fields
            ->byForm($formId);
    }

    public function bySection(
        int $sectionId
    ): array {
        return $this->fields
            ->bySection($sectionId);
    }

    public function find(
        int $id
    ): ?array {
        return $this->fields
            ->find($id);
    }

    public function create(
        int $formId,
        array $data
    ): void {
        if ($formId <= 0) {
            throw new RuntimeException(
                'Invalid form ID.'
            );
        }

        $sectionId = (int) (
            $data['section_id']
            ?? 0
        );

        if ($sectionId <= 0) {
            throw new RuntimeException(
                'Target section is required.'
            );
        }

        $fieldLabel = trim(
            (string) (
                $data['field_label']
                ?? ''
            )
        );

        if ($fieldLabel === '') {
            throw new RuntimeException(
                'Field label is required.'
            );
        }

        $fieldType = strtolower(
            trim(
                (string) (
                    $data['field_type']
                    ?? ''
                )
            )
        );

        if (
            !in_array(
                $fieldType,
                self::ALLOWED_TYPES,
                true
            )
        ) {
            throw new RuntimeException(
                'Invalid field type.'
            );
        }

        $fieldName = $this->makeFieldName(
            $fieldLabel
        );

        $fieldName = $this->uniqueFieldName(
            $formId,
            $fieldName
        );

        $columnWidth = (int) (
            $data['column_width']
            ?? 12
        );

        if (
            !in_array(
                $columnWidth,
                self::ALLOWED_WIDTHS,
                true
            )
        ) {
            $columnWidth = 12;
        }
$validationRules = $this->buildValidationRules(
    $fieldType,
    $data
);
        $now = date(
            'Y-m-d H:i:s'
        );

        $this->fields->create([
            'form_id' =>
                $formId,

            'section_id' =>
                $sectionId,

            'field_name' =>
                $fieldName,

            'field_label' =>
                $fieldLabel,

            'field_type' =>
                $fieldType,

            'placeholder' =>
                $this->nullableString(
                    $data['placeholder']
                    ?? null
                ),

            'help_text' =>
                $this->nullableString(
                    $data['help_text']
                    ?? null
                ),

            'default_value' =>
                $this->nullableString(
                    $data['default_value']
                    ?? null
                ),

            'is_required' =>
                !empty(
                    $data['is_required']
                )
                    ? 1
                    : 0,

'validation_rules' => $validationRules,

            'sort_order' =>
                $this->fields
                    ->nextSortOrder(
                        $sectionId
                    ),

            'column_width' =>
                $columnWidth,

            'status' =>
                1,

            'created_at' =>
                $now,

            'updated_at' =>
                $now
        ]);
    }

    public function update(
        int $id,
        array $data
    ): void {
        $field = $this->fields
            ->find($id);
$fieldType = (string) (
    $field['field_type']
    ?? ''
);

$validationRules = $this->buildValidationRules(
    $fieldType,
    $data
);
        if ($field === null) {
            throw new RuntimeException(
                'Dynamic form field not found.'
            );
        }

        $fieldLabel = trim(
            (string) (
                $data['field_label']
                ?? ''
            )
        );

        if ($fieldLabel === '') {
            throw new RuntimeException(
                'Field label is required.'
            );
        }

        $columnWidth = (int) (
            $data['column_width']
            ?? 12
        );

        if (
            !in_array(
                $columnWidth,
                self::ALLOWED_WIDTHS,
                true
            )
        ) {
            $columnWidth = 12;
        }

        $this->fields->update(
            $id,
            [
                'field_label' =>
                    $fieldLabel,

                'placeholder' =>
                    $this->nullableString(
                        $data['placeholder']
                        ?? null
                    ),

                'help_text' =>
                    $this->nullableString(
                        $data['help_text']
                        ?? null
                    ),

                'default_value' =>
                    $this->nullableString(
                        $data['default_value']
                        ?? null
                    ),

                'is_required' =>
                    !empty(
                        $data['is_required']
                    )
                        ? 1
                        : 0,

'validation_rules' => $validationRules,

                'column_width' =>
                    $columnWidth,

                'updated_at' =>
                    date('Y-m-d H:i:s')
            ]
        );
    }

    private function makeFieldName(
        string $label
    ): string {
        $name = strtolower($label);

        $name = preg_replace(
            '/[^a-z0-9]+/',
            '_',
            $name
        );

        $name = trim(
            (string) $name,
            '_'
        );

        if ($name === '') {
            $name = 'field';
        }

        return $name;
    }

    private function uniqueFieldName(
        int $formId,
        string $baseName
    ): string {
        $fieldName = $baseName;
        $counter = 2;

        while (
            $this->fields->findByName(
                $formId,
                $fieldName
            ) !== null
        ) {
            $fieldName =
                $baseName
                . '_'
                . $counter;

            $counter++;
        }

        return $fieldName;
    }
private function buildValidationRules(
    string $fieldType,
    array $data
): ?string {

    $rules = [];

    switch ($fieldType) {

        case 'number':

            $rules = [
                'min'  => $data['number_min'] ?? '',
                'max'  => $data['number_max'] ?? '',
                'step' => $data['number_step'] ?? ''
            ];

            break;

        case 'date':

            $rules = [
                'min_date' => $data['date_min'] ?? '',
                'max_date' => $data['date_max'] ?? ''
            ];

            break;

        case 'time':

            $rules = [
                'min_time' => $data['time_min'] ?? '',
                'max_time' => $data['time_max'] ?? ''
            ];

            break;

        case 'file':

            $rules = [
                'allowed_extensions' =>
                    $data['allowed_extensions'] ?? [],

                'max_size' =>
                    $data['max_file_size'] ?? '',

                'multiple' =>
                    !empty($data['multiple_upload'])
            ];

            break;

        default:

            return null;
    }

    return json_encode(
        $rules,
        JSON_UNESCAPED_UNICODE
    );
}
    private function nullableString(
        mixed $value
    ): ?string {
        $value = trim(
            (string) $value
        );

        return $value !== ''
            ? $value
            : null;
    }
}