<?php

namespace App\Services\Connections;

use App\Models\ConnectionModel;
use App\Services\Support\ActivityLogger;
use Config\Database;

class ConnectionService
{
    private ConnectionModel $connections;
    private ActivityLogger $activity;

    public function __construct()
    {
        $this->connections = new ConnectionModel();
        $this->activity    = new ActivityLogger();
    }

    public function sendRequest(int $requesterId, int $recipientId): array
    {
        if ($requesterId === $recipientId) {
            throw new \InvalidArgumentException('You cannot connect with yourself.');
        }

        $existing = $this->existingBetween($requesterId, $recipientId);
        if ($existing) {
            if ($existing['status'] === 'accepted') {
                throw new \RuntimeException('You are already connected.');
            }
            if ($existing['status'] === 'pending') {
                throw new \RuntimeException('A connection request is already pending between you two.');
            }
            $this->connections->update($existing['id'], [
                'requester_user_id' => $requesterId,
                'recipient_user_id' => $recipientId,
                'status'            => 'pending',
                'created_at'        => date('Y-m-d H:i:s'),
                'responded_at'      => null,
            ]);
            $id = $existing['id'];
        } else {
            $id = $this->connections->insert([
                'requester_user_id' => $requesterId,
                'recipient_user_id' => $recipientId,
                'status'            => 'pending',
                'created_at'        => date('Y-m-d H:i:s'),
            ], true);
        }

        $this->activity->log($requesterId, null, null, 'connection_request_sent', ['recipient_user_id' => $recipientId]);

        return $this->connections->find($id);
    }

    public function acceptRequest(int $connectionId, int $respondingUserId): array
    {
        $connection = $this->connections->find($connectionId);
        if (! $connection || (int) $connection['recipient_user_id'] !== $respondingUserId) {
            throw new \RuntimeException('Connection request not found.');
        }
        if ($connection['status'] !== 'pending') {
            throw new \RuntimeException('This request has already been responded to.');
        }

        $this->connections->update($connectionId, ['status' => 'accepted', 'responded_at' => date('Y-m-d H:i:s')]);
        $this->activity->log($respondingUserId, null, null, 'connection_request_accepted', ['connection_id' => $connectionId, 'requester_user_id' => $connection['requester_user_id']]);

        return $this->connections->find($connectionId);
    }

    public function rejectRequest(int $connectionId, int $respondingUserId): void
    {
        $connection = $this->connections->find($connectionId);
        if (! $connection || (int) $connection['recipient_user_id'] !== $respondingUserId) {
            throw new \RuntimeException('Connection request not found.');
        }
        if ($connection['status'] !== 'pending') {
            throw new \RuntimeException('This request has already been responded to.');
        }

        $this->connections->update($connectionId, ['status' => 'rejected', 'responded_at' => date('Y-m-d H:i:s')]);
        $this->activity->log($respondingUserId, null, null, 'connection_request_rejected', ['connection_id' => $connectionId]);
    }

    public function removeConnection(int $connectionId, int $actingUserId): void
    {
        $connection = $this->connections->find($connectionId);
        if (! $connection || ((int) $connection['requester_user_id'] !== $actingUserId && (int) $connection['recipient_user_id'] !== $actingUserId)) {
            throw new \RuntimeException('Connection not found.');
        }
        $this->connections->delete($connectionId);
        $this->activity->log($actingUserId, null, null, 'connection_removed', ['connection_id' => $connectionId]);
    }

    public function listConnections(int $userId): array
    {
        $db = Database::connect();
        $rows = $db->table('connections c')
            ->select("c.id, c.responded_at,
                CASE WHEN c.requester_user_id = {$userId} THEN c.recipient_user_id ELSE c.requester_user_id END as other_user_id", false)
            ->where('c.status', 'accepted')
            ->groupStart()
                ->where('c.requester_user_id', $userId)
                ->orWhere('c.recipient_user_id', $userId)
            ->groupEnd()
            ->orderBy('c.responded_at', 'DESC')
            ->get()->getResultArray();

        return $this->enrichWithProfiles($rows, 'other_user_id');
    }

    public function pendingReceived(int $userId): array
    {
        $db = Database::connect();
        $rows = $db->table('connections c')
            ->select('c.id, c.created_at, c.requester_user_id as other_user_id')
            ->where('c.recipient_user_id', $userId)
            ->where('c.status', 'pending')
            ->orderBy('c.created_at', 'DESC')
            ->get()->getResultArray();

        return $this->enrichWithProfiles($rows, 'other_user_id');
    }

    public function pendingSent(int $userId): array
    {
        $db = Database::connect();
        $rows = $db->table('connections c')
            ->select('c.id, c.created_at, c.recipient_user_id as other_user_id')
            ->where('c.requester_user_id', $userId)
            ->where('c.status', 'pending')
            ->orderBy('c.created_at', 'DESC')
            ->get()->getResultArray();

        return $this->enrichWithProfiles($rows, 'other_user_id');
    }

    public function statusBetween(int $viewerId, int $targetId): ?array
    {
        if ($viewerId === $targetId) {
            return null;
        }
        $existing = $this->existingBetween($viewerId, $targetId);
        if (! $existing) {
            return ['status' => 'none'];
        }
        return [
            'status'          => $existing['status'],
            'connection_id'   => $existing['id'],
            'is_requester'    => (int) $existing['requester_user_id'] === $viewerId,
        ];
    }

    private function existingBetween(int $userA, int $userB): ?array
    {
        return $this->connections->groupStart()
            ->where('requester_user_id', $userA)->where('recipient_user_id', $userB)
            ->groupEnd()
            ->orGroupStart()
                ->where('requester_user_id', $userB)->where('recipient_user_id', $userA)
            ->groupEnd()
            ->get()->getRowArray();
    }

    private function enrichWithProfiles(array $rows, string $idKey): array
    {
        if (empty($rows)) {
            return [];
        }
        $db = Database::connect();
        foreach ($rows as &$row) {
            $user = $db->table('users u')
                ->select('u.id, u.name, u.username, u.profile_photo_path, r.slug as role_slug, a.company_name, a.logo_path, a.verification_status')
                ->join('roles r', 'r.id = u.role_id')
                ->join('agencies a', 'a.id = u.agency_id', 'left')
                ->where('u.id', $row[$idKey])
                ->get()->getRowArray();
            $row['user'] = $user;
        }
        return $rows;
    }
}
