<?php

namespace App\Services\AgentSettlement;

use App\Support\AgentSettlementPeriodWindow;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

final class AgentSettlementPeriodOpenService
{
    /**
     * @param  array{admin_site_id: int, period_start: string, period_end: string}  $data
     * @return object{id: int, admin_site_id: int, period_start: string, period_end: string, status: string}
     */
    public function open(array $data): object
    {
        $siteId = (int) $data['admin_site_id'];
        [$start, $end] = AgentSettlementPeriodWindow::normalizeInputBounds(
            (string) $data['period_start'],
            (string) $data['period_end'],
        );

        $existingSameRange = DB::table('settlement_periods')
            ->where('admin_site_id', $siteId)
            ->where('status', 'open')
            ->where('period_start', $start)
            ->where('period_end', $end)
            ->orderByDesc('id')
            ->first();

        if ($existingSameRange !== null) {
            throw ValidationException::withMessages([
                'period_start' => ['period_already_open'],
            ]);
        }

        $otherOpen = DB::table('settlement_periods')
            ->where('admin_site_id', $siteId)
            ->where('status', 'open')
            ->orderByDesc('id')
            ->first();

        if ($otherOpen !== null) {
            throw ValidationException::withMessages([
                'period_start' => ['period_site_has_open'],
            ]);
        }

        if ($this->overlapsExistingPeriod($siteId, $start, $end)) {
            throw ValidationException::withMessages([
                'period_start' => ['period_overlaps_existing'],
            ]);
        }

        $id = (int) DB::table('settlement_periods')->insertGetId([
            'admin_site_id' => $siteId,
            'period_start' => $start,
            'period_end' => $end,
            'status' => 'open',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        $row = DB::table('settlement_periods')->where('id', $id)->first();
        if ($row === null) {
            throw new \RuntimeException('period_insert_failed');
        }

        return $row;
    }

    private function overlapsExistingPeriod(int $siteId, string $start, string $end): bool
    {
        return DB::table('settlement_periods')
            ->where('admin_site_id', $siteId)
            ->where('period_start', '<=', $end)
            ->where('period_end', '>=', $start)
            ->exists();
    }
}
