<?php

namespace App\Validation;

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

class GpPracticeValidator
{
    /**
     * The only keys accepted in a gp_practice payload.
     */
    public const ALLOWED_KEYS = [
        'id',
        'name',
        'org_id',
        'address_line_1',
        'address_line_2',
        'town',
        'county',
        'postcode',
        'telephone_number',
        'manual_gp_practice',
    ];

    /**
     * Laravel validation rules for each field.
     */
    private static function rules(): array
    {
        return [
            'id'                 => ['nullable', 'integer'],
            'name'               => ['nullable', 'string', 'max:255'],
            'org_id'             => ['nullable', 'string', 'max:20'],
            'address_line_1'     => ['nullable', 'string', 'max:255'],
            'address_line_2'     => ['nullable', 'string', 'max:255'],
            'town'               => ['nullable', 'string', 'max:255'],
            'county'             => ['nullable', 'string', 'max:255'],
            'postcode'           => ['nullable', 'string', 'max:20'],
            'telephone_number'   => ['nullable', 'string', 'max:30'],
            'manual_gp_practice' => ['nullable', 'integer', 'in:0,1'],
        ];
    }

    /**
     * Validate a gp_practice payload.
     *
     * Rejects any keys not in the ALLOWED_KEYS list, then validates
     * each known field against its type/length rules.
     *
     * @param  mixed  $data  The raw gp_practice input (expected array/object).
     * @return array  The validated and filtered data containing only allowed keys.
     *
     * @throws ValidationException  When the payload is not an array/object,
     *                              contains unexpected keys, or fails field validation.
     */
    public static function validate(mixed $data): array
    {
        if (is_object($data)) {
            $data = (array) $data;
        }

        if (!is_array($data)) {
            throw ValidationException::withMessages([
                'gp_practice' => ['The gp_practice field must be an array or object.'],
            ]);
        }

        $unexpectedKeys = array_diff(array_keys($data), self::ALLOWED_KEYS);

        if (!empty($unexpectedKeys)) {
            throw ValidationException::withMessages([
                'gp_practice' => [
                    'The gp_practice payload contains unexpected keys: ' . implode(', ', $unexpectedKeys),
                ],
            ]);
        }

        $validator = Validator::make($data, self::rules());

        if ($validator->fails()) {
            throw ValidationException::withMessages(
                $validator->errors()->toArray()
            );
        }

        // Return only allowed keys (strip anything that somehow survived)
        return array_intersect_key($data, array_flip(self::ALLOWED_KEYS));
    }
}
