<?php

declare(strict_types=1);

namespace App\Modules\Administration\Services;

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

final class PositionService
{
    public function __construct(
        private PositionRepository $positions
    ) {
    }

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

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

    public function departments(): array
    {
        return $this->positions->departments();
    }

    public function create(array $data): void
    {
        $departmentId = (int) (
            $data['department_id'] ?? 0
        );

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

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

        if ($departmentId < 1) {
            throw new RuntimeException(
                'Department is required.'
            );
        }

        if ($code === '') {
            throw new RuntimeException(
                'Position code is required.'
            );
        }

        if ($name === '') {
            throw new RuntimeException(
                'Position name is required.'
            );
        }

        if (
            $this->positions->findByCode($code)
            !== null
        ) {
            throw new RuntimeException(
                'Position code already exists.'
            );
        }

        if (
            $this->positions->findByName(
                $departmentId,
                $name
            ) !== null
        ) {
            throw new RuntimeException(
                'Position already exists in this department.'
            );
        }

        $this->positions->create([
            'department_id' => $departmentId,
            'position_code' => $code,
            'position_name' => $name,
            '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 {
        $position = $this->positions->find(
            $id
        );

        if ($position === null) {
            throw new RuntimeException(
                'Position not found.'
            );
        }

        $departmentId = (int) (
            $data['department_id'] ?? 0
        );

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

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

        if (
            $departmentId < 1
            || $code === ''
            || $name === ''
        ) {
            throw new RuntimeException(
                'Department, position code and position name are required.'
            );
        }

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

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

        $existingName =
            $this->positions->findByName(
                $departmentId,
                $name
            );

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

        $this->positions->update(
            $id,
            [
                'department_id' => $departmentId,
                'position_code' => $code,
                'position_name' => $name,
                'status' => isset($data['status'])
                    ? 1
                    : 0,
                'updated_at' => date(
                    'Y-m-d H:i:s'
                )
            ]
        );
    }

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

        if ($position === null) {
            throw new RuntimeException(
                'Position not found.'
            );
        }

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

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