<?php

declare(strict_types=1);

namespace App\Modules\Administration\Services;

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

final class StateService
{
    public function __construct(
        private StateRepository $states
    ) {
    }

    public function all(): array
    {
        return $this->states->all();
    }

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

    public function create(array $data): void
    {
        $code = strtoupper(
            trim((string) ($data['state_code'] ?? ''))
        );

        $name = trim(
            (string) ($data['state_name'] ?? '')
        );

        $type = strtoupper(
            trim(
                (string) (
                    $data['administrative_type']
                    ?? 'STATE'
                )
            )
        );

        if ($code === '' || $name === '') {
            throw new RuntimeException(
                'Code and name are required.'
            );
        }

        if (
            !in_array(
                $type,
                [
                    'STATE',
                    'ADMINISTRATIVE_AREA'
                ],
                true
            )
        ) {
            throw new RuntimeException(
                'Invalid administrative type.'
            );
        }

        if ($this->states->findByCode($code)) {
            throw new RuntimeException(
                'Code already exists.'
            );
        }

        if ($this->states->findByName($name)) {
            throw new RuntimeException(
                'Name already exists.'
            );
        }

        $this->states->create([
            'state_code' => $code,
            'state_name' => $name,
            'administrative_type' => $type,
            'status' => 1,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s')
        ]);
    }

    public function update(
        int $id,
        array $data
    ): void {
        $state = $this->states->find($id);

        if ($state === null) {
            throw new RuntimeException(
                'State or Administrative Area not found.'
            );
        }

        $code = strtoupper(
            trim((string) ($data['state_code'] ?? ''))
        );

        $name = trim(
            (string) ($data['state_name'] ?? '')
        );

        $type = strtoupper(
            trim(
                (string) (
                    $data['administrative_type']
                    ?? 'STATE'
                )
            )
        );

        if ($code === '' || $name === '') {
            throw new RuntimeException(
                'Code and name are required.'
            );
        }

        if (
            !in_array(
                $type,
                [
                    'STATE',
                    'ADMINISTRATIVE_AREA'
                ],
                true
            )
        ) {
            throw new RuntimeException(
                'Invalid administrative type.'
            );
        }

        $existingCode =
            $this->states->findByCode($code);

        if (
            $existingCode !== null
            && (int) $existingCode['id'] !== $id
        ) {
            throw new RuntimeException(
                'Code already exists.'
            );
        }

        $existingName =
            $this->states->findByName($name);

        if (
            $existingName !== null
            && (int) $existingName['id'] !== $id
        ) {
            throw new RuntimeException(
                'Name already exists.'
            );
        }

        $this->states->update(
            $id,
            [
                'state_code' => $code,
                'state_name' => $name,
                'administrative_type' => $type,
                'status' => isset($data['status'])
                    ? 1
                    : 0,
                'updated_at' => date('Y-m-d H:i:s')
            ]
        );
    }

    public function toggleStatus(int $id): void
    {
        $state = $this->states->find($id);

        if ($state === null) {
            throw new RuntimeException(
                'State or Administrative Area not found.'
            );
        }

        $newStatus =
            (int) $state['status'] === 1
                ? 0
                : 1;

        $this->states->setStatus(
            $id,
            $newStatus
        );
    }
}