<?php

namespace App\Components\Dialler;

use App\Enum\Communication\CommunicationChannel;
use App\Enum\Communication\CommunicationStatus;
use App\Models\Communication\Communication;
use App\Models\Communication\Voicemail;
use App\Models\Dialler\AgentStatus;
use App\Models\Solicitor\Solicitor;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
use Livewire\WithPagination;

class Dashboard extends Component
{
    use WithPagination;

    protected string $paginationTheme = 'bootstrap';

    public string $callSearch = '';

    public string $callDirection = '';

    public string $callStatus = '';

    public string $callerType = '';

    public string $callDateFrom = '';

    public string $callDateTo = '';

    public function updatedCallSearch(): void
    {
        $this->resetPage('callLogPage');
    }

    public function updatedCallDirection(): void
    {
        $this->resetPage('callLogPage');
    }

    public function updatedCallStatus(): void
    {
        $this->resetPage('callLogPage');
    }

    public function updatedCallerType(): void
    {
        $this->resetPage('callLogPage');
    }

    public function updatedCallDateFrom(): void
    {
        $this->resetPage('callLogPage');
    }

    public function updatedCallDateTo(): void
    {
        $this->resetPage('callLogPage');
    }

    public function resetCallFilters(): void
    {
        $this->reset([
            'callSearch',
            'callDirection',
            'callStatus',
            'callerType',
            'callDateFrom',
            'callDateTo',
        ]);

        $this->resetPage('callLogPage');
    }

    public function markListened(int $voicemailId): void
    {
        $solicitorId = app(Solicitor::class)?->id;

        Voicemail::query()
            ->where('solicitor_id', $solicitorId)
            ->findOrFail($voicemailId)
            ->update([
                'is_listened' => true,
            ]);
    }

    public function render()
    {
        $solicitorId = app(Solicitor::class)?->id;

        $activeCalls = Communication::query()
            ->with([
                'call',
                'agent:id,name_first,name_last',
                'communicable',
            ])
            ->where('solicitor_id', $solicitorId)
            ->whereIn('status', [
                CommunicationStatus::InProgress->value,
                CommunicationStatus::Ringing->value,
            ])
            ->latest('started_at')
            ->get();

        $canViewAllWorkspaces = (bool) auth()
            ->user()
            ?->can('communications.agents.view.all_workspaces');

        $agentStatusQuery = AgentStatus::query()
            ->with('agent:id,name_first,name_last')
            ->orderByRaw(
                "FIELD(status, 'available', 'busy', 'wrap_up', " .
                "'do_not_disturb', 'offline')"
            );

        if ($canViewAllWorkspaces) {
            $agentStatusQuery->with('solicitor:id,name');
        } else {
            $agentStatusQuery->where(
                'solicitor_id',
                $solicitorId,
            );
        }

        $agentStatuses = $agentStatusQuery->get();

        $missedCalls = Communication::query()
            ->with([
                'call',
                'communicable',
            ])
            ->where('solicitor_id', $solicitorId)
            ->where(
                'status',
                CommunicationStatus::Missed->value,
            )
            ->whereDate('created_at', today())
            ->latest('started_at')
            ->get();

        $voicemails = Voicemail::query()
            ->with([
                'communication.communicable',
                'recording',
                'assignedAgent:id,name_first,name_last',
            ])
            ->where('solicitor_id', $solicitorId)
            ->where('is_listened', false)
            ->latest('received_at')
            ->get();

        /*
         * Call Log
         *
         * Every query remains restricted to the solicitor currently being
         * viewed. Unknown callers are included because communicable_type and
         * communicable_id are allowed to be null.
         */
        $callLogs = Communication::query()
            ->with([
                'call.answeredByAgent:id,name_first,name_last',
                'communicable',
                'agent:id,name_first,name_last',
            ])
            ->where('solicitor_id', $solicitorId)
            ->where(
                'channel',
                CommunicationChannel::Voice->value,
            )
            ->whereHas('call')
            ->when(
                filled($this->callSearch),
                function (Builder $query): void {
                    $search = trim($this->callSearch);

                    $query->where(
                        function (Builder $query) use ($search): void {
                            $query
                                ->where(
                                    'preview',
                                    'like',
                                    "%{$search}%",
                                )
                                ->orWhereHas(
                                    'call',
                                    function (Builder $query) use ($search): void {
                                        $query
                                            ->where(
                                                'from_number',
                                                'like',
                                                "%{$search}%",
                                            )
                                            ->orWhere(
                                                'to_number',
                                                'like',
                                                "%{$search}%",
                                            )
                                            ->orWhere(
                                                'target_label',
                                                'like',
                                                "%{$search}%",
                                            );
                                    },
                                );
                        },
                    );
                },
            )
            ->when(
                filled($this->callDirection),
                fn (Builder $query) => $query->where(
                    'direction',
                    $this->callDirection,
                ),
            )
            ->when(
                filled($this->callStatus),
                fn (Builder $query) => $query->where(
                    'status',
                    $this->callStatus,
                ),
            )
            ->when(
                $this->callerType === 'known',
                fn (Builder $query) => $query
                    ->whereNotNull('communicable_type')
                    ->whereNotNull('communicable_id'),
            )
            ->when(
                $this->callerType === 'unknown',
                fn (Builder $query) => $query->where(
                    function (Builder $query): void {
                        $query
                            ->whereNull('communicable_type')
                            ->orWhereNull('communicable_id');
                    },
                ),
            )
            ->when(
                filled($this->callDateFrom),
                fn (Builder $query) => $query->whereDate(
                    'started_at',
                    '>=',
                    $this->callDateFrom,
                ),
            )
            ->when(
                filled($this->callDateTo),
                fn (Builder $query) => $query->whereDate(
                    'started_at',
                    '<=',
                    $this->callDateTo,
                ),
            )
            ->latest('started_at')
            ->paginate(
                perPage: 15,
                pageName: 'callLogPage',
            );

        $workspaceStatuses = $canViewAllWorkspaces
            ? AgentStatus::query()
                ->where('solicitor_id', $solicitorId)
                ->get(['status'])
            : $agentStatuses;

        $availableCount = $workspaceStatuses
            ->where('status', 'available')
            ->count();

        $workspaceAgentCount = $workspaceStatuses->count();

        return view('components.dialler.dashboard', compact(
            'activeCalls',
            'agentStatuses',
            'missedCalls',
            'voicemails',
            'callLogs',
            'availableCount',
            'workspaceAgentCount',
            'canViewAllWorkspaces',
        ));
    }
}