<?php

namespace App\Console\Commands;

use App\Models\Client\Client;
use App\Models\Claim\Claim;
use App\Models\Communication\Call;
use App\Models\Communication\Communication;
use App\Services\WipService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class GenerateCallWipEntries extends Command
{
    protected $signature = 'wip:generate-call-entries';

    protected $description = 'Generate WIP entries for completed Twilio calls';

    public function handle(WipService $wipService): int
    {
        $calls = Call::query()
            ->with([
                'communication.communicable',
                'assignedAgent',
                'answeredByAgent',
                'recordings',
            ])
            ->where('wip_created', false)
            ->whereNotNull('connected_at')
            ->where(function ($query) {
                $query->whereNotNull('assigned_agent_id')
                    ->orWhereNotNull('answered_by_agent_id');
            })
            ->whereHas('recordings', function ($query) {
                $query->where('duration', '>', 0);
            })
            ->where('created_at', '>=', now()->subDays(30))
            ->get();

        $created = 0;
        $skipped = 0;

        foreach ($calls as $call) {
            $communication = $call->communication;

            if (! $communication || $this->shouldSkipCall($call)) {
                $skipped++;
                continue;
            }

            $recording = $call->recordings
                ->where('duration', '>', 0)
                ->sortByDesc('duration')
                ->first();

            if (! $recording) {
                $skipped++;
                continue;
            }

            $userId = $call->assigned_agent_id ?? $call->answered_by_agent_id;

            if (! $userId) {
                $skipped++;
                continue;
            }

            $connectedAt = Carbon::parse($call->connected_at);
            $seconds = (int) $recording->duration;
            $endedAt = $connectedAt->copy()->addSeconds($seconds);

            $clientId = $this->resolveClientId($communication);
            $claimId = $this->resolveClaimId($communication);
            
            
            $solicitorId = $call->solicitor_id ?? $communication->solicitor_id;

            if (! $solicitorId && $clientId) {
                $solicitorId = Client::find($clientId)?->solicitor_id;
            }
            
            if (! $solicitorId) {
                $skipped++;
                continue;
            }
            

            DB::transaction(function () use (
                $call,
                $communication,
                $wipService,
                $clientId,
                $claimId,
                $seconds,
                $connectedAt,
                $endedAt,
                $userId,
                $solicitorId,
            ) {
                $wipService->create([
                    'solicitor_id' => $solicitorId,
                    'client_id' => $clientId,
                    'claim_id' => $claimId,
                    'user_id' => $userId,
                    'activity_type' => 'call',
                    'seconds' => $seconds,
                    'description' => 'Call',
                    'started_at' => $connectedAt,
                    'ended_at' => $endedAt,
                    'is_manual' => false,
                ], $communication);

                $call->forceFill([
                    'wip_created' => true,
                ])->save();
            });

            $created++;
        }

        $this->info("Created {$created} call WIP entries. Skipped {$skipped} calls.");

        return self::SUCCESS;
    }

    private function shouldSkipCall(Call $call): bool
    {
        $lastStatus = collect($call->meta['twilio_status_callbacks'] ?? [])
            ->sortBy(fn ($callback) => (int) ($callback['SequenceNumber'] ?? 0))
            ->last();

        return ($lastStatus['CallStatus'] ?? null) === 'no-answer';
    }

    private function resolveClientId(Communication $communication): ?int
    {
        $owner = $communication->communicable;

        if (! $owner instanceof Model) {
            return null;
        }

        if ($owner instanceof Client) {
            return $owner->id;
        }

        if ($owner instanceof Claim) {
            return $owner->client_id;
        }

        if (isset($owner->client_id)) {
            return $owner->client_id;
        }

        if (method_exists($owner, 'client')) {
            return $owner->client?->id;
        }

        if (method_exists($owner, 'claim')) {
            return $owner->claim?->client_id;
        }

        return null;
    }

    private function resolveClaimId(Communication $communication): ?int
    {
        $owner = $communication->communicable;

        if (! $owner instanceof Model) {
            return $communication->claim_id;
        }

        if ($communication->claim_id) {
            return $communication->claim_id;
        }

        if ($owner instanceof Claim) {
            return $owner->id;
        }

        if ($owner instanceof Client) {
            return $owner->claim?->id;
        }

        if (isset($owner->claim_id)) {
            return $owner->claim_id;
        }

        if (method_exists($owner, 'claim')) {
            return $owner->claim?->id;
        }

        return null;
    }
}