<?php

namespace App\Services;

use App\Contracts\AuditLogServiceInterface;
use App\Contracts\FingerprintMachineRepositoryInterface;
use App\DTO\MachineDTO;
use App\Models\FingerprintMachine;
use Illuminate\Support\Facades\Log;
use App\Services\Fingerprint\FingerprintDeviceManager;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Auth;

class FingerprintMachineService
{
    public function __construct(
        protected FingerprintMachineRepositoryInterface $machineRepository,
        protected AuditLogServiceInterface $auditLogService,
        protected FingerprintDeviceManager $deviceManager
    ) {}

    public function getAllMachines(): Collection
    {
        return $this->machineRepository->getAll();
    }

    public function createMachine(MachineDTO $machineDTO): FingerprintMachine
    {
        $machine = $this->machineRepository->create($machineDTO);
        $user = Auth::user();
        $this->auditLogService->log($user, 'MACHINE_CREATED', "Menambahkan mesin fingerprint baru: {$machine->name} ({$machine->ip_address}:{$machine->port})");

        return $machine;
    }

    public function updateMachine(int $id, MachineDTO $machineDTO): FingerprintMachine
    {
        $machine = $this->machineRepository->update($id, $machineDTO);
        $user = Auth::user();
        $this->auditLogService->log($user, 'MACHINE_UPDATED', "Memperbarui konfigurasi mesin: {$machine->name} ({$machine->ip_address}:{$machine->port})");

        return $machine;
    }

    public function deleteMachine(int $id): bool
    {
        $machine = $this->machineRepository->findById($id);
        if ($machine) {
            $machineName = $machine->name;
            $deleted = $this->machineRepository->delete($id);
            if ($deleted) {
                $user = Auth::user();
                $this->auditLogService->log($user, 'MACHINE_DELETED', "Menghapus mesin fingerprint: {$machineName} (ID: {$id})");
            }
            return $deleted;
        }

        return false;
    }

    /**
     * Diagnostic Bertingkat (Layered Diagnostic)
     */
    public function testConnectionDetailed(FingerprintMachine $machine): array
    {
        $provider = $this->deviceManager->make($machine);

        $tcp = $provider->testTcpConnection($machine);
        $proto = $tcp['tcp_connected'] ? $provider->testProtocol($machine) : [
            'protocol_detected' => false,
            'protocol_name' => strtolower($machine->protocol ?? 'fingerspot_local'),
            'message' => 'TCP Connection unreachable',
        ];

        $info = $tcp['tcp_connected'] ? $provider->getDeviceInfo($machine) : [
            'success' => false,
            'device_info' => [],
            'message' => 'TCP Connection unreachable',
        ];

        $isOnline = $tcp['tcp_connected'];
        $newStatus = $isOnline ? 'online' : 'offline';
        $now = now()->toDateTimeString();

        $this->machineRepository->updateStatus($machine, $newStatus, $isOnline ? $now : null);

        if ($isOnline && !empty($info['device_info'])) {
            $machine->update([
                'latency_ms' => $tcp['latency_ms'] ?? 0,
                'device_info' => $info['device_info'],
            ]);
        }

        $user = Auth::user();
        $target = in_array($machine->connection_type, ['local_connector'])
            ? ($machine->connector_host ?: $machine->ip_address) . ':' . ($machine->connector_port ?: '8000') . ' (via Connector)'
            : $machine->ip_address . ':' . $machine->port;
        $this->auditLogService->log(
            $user,
            'MACHINE_TEST_CONNECTION',
            "Uji koneksi mesin {$machine->name} ({$target}): Status -> " . strtoupper($newStatus)
        );

        return [
            'is_online' => $isOnline,
            'tcp' => $tcp,
            'protocol' => $proto,
            'device_info' => $info,
        ];
    }

    /**
     * Legacy boolean wrapper compatibility
     */
    public function testConnection(FingerprintMachine $machine): bool
    {
        $res = $this->testConnectionDetailed($machine);
        return $res['is_online'];
    }

    public function testAllConnections(): array
    {
        $machines = $this->getAllMachines();
        $results = [];

        foreach ($machines as $machine) {
            $diag = $this->testConnectionDetailed($machine);
            $results[$machine->id] = [
                'name' => $machine->name,
                'is_online' => $diag['is_online'],
                'diagnostic' => $diag,
            ];
        }

        return $results;
    }



    /**
     * Sinkronisasi waktu mesin fingerprint dengan waktu server
     */
    public function syncMachineTime(FingerprintMachine $machine): array
    {
        $provider = $this->deviceManager->make($machine);
        $res = $provider->setDeviceTime($machine);

        $user = Auth::user();
        if ($res['success']) {
            $this->auditLogService->log(
                $user,
                'MACHINE_SYNC_TIME',
                "Sinkronisasi waktu mesin {$machine->name} berhasil."
            );
        } else {
            $this->auditLogService->log(
                $user,
                'MACHINE_SYNC_TIME_FAILED',
                "Sinkronisasi waktu mesin {$machine->name} gagal: {$res['message']}"
            );
        }

        return $res;
    }
}
