<?php

namespace App\Domains\Tasks\Actions;

use App\Domains\Conversations\Models\Message;
use App\Domains\Orders\Models\Order;
use App\Domains\Tasks\Models\FollowUpCampaign;
use App\Domains\Tasks\Models\FollowUpCampaignRecipient;
use App\Models\User;

class ExecuteFollowUpCampaignAction
{
    public function __construct(
        protected SendFollowUpCampaignAction $sendCampaign,
    ) {
    }

    /**
     * @param array<int, array<string, mixed>> $recipients
     */
    public function execute(FollowUpCampaign $campaign, User $actor, array $recipients): array
    {
        $result = $this->sendCampaign->execute($actor, $recipients, $campaign->message_template);

        foreach ($recipients as $recipient) {
            $contactId = $recipient['contactId'] ?? null;
            $conversationId = $recipient['conversationId'] ?? null;
            $message = str_replace(
                ['{name}', '{company}'],
                [(string) ($recipient['name'] ?? 'there'), $actor->tenant?->company_name ?? 'our store'],
                $campaign->message_template
            );

            FollowUpCampaignRecipient::query()->create([
                'tenant_id' => $actor->tenant_id,
                'campaign_id' => $campaign->getKey(),
                'contact_id' => $contactId,
                'conversation_id' => $conversationId,
                'channel' => $recipient['channel'] ?? null,
                'status' => 'sent',
                'reasons_json' => $recipient['reasons'] ?? [],
                'message_preview' => $message,
                'sent_at' => now(),
            ]);
        }

        $this->refreshMetrics($campaign);

        $campaign->update([
            'status' => $campaign->is_auto_enabled ? 'scheduled' : 'sent',
            'last_run_at' => now(),
            'last_sent_count' => $result['sent'],
            'last_skipped_count' => $result['skipped'],
            'total_sent_count' => (int) $campaign->total_sent_count + (int) $result['sent'],
            'total_skipped_count' => (int) $campaign->total_skipped_count + (int) $result['skipped'],
            'next_run_at' => $campaign->is_auto_enabled
                ? $this->nextRunAt($campaign->frequency ?? 'daily')
                : $campaign->next_run_at,
            'approved_at' => null,
            'approved_by' => null,
        ]);

        return $result;
    }

    public function refreshMetrics(FollowUpCampaign $campaign): void
    {
        $campaign->loadMissing('recipients');
        $replied = 0;
        $converted = 0;

        foreach ($campaign->recipients as $recipient) {
            $sentAt = $recipient->sent_at;
            if (! $sentAt) {
                continue;
            }

            $hasReply = $recipient->conversation_id
                ? Message::query()
                    ->where('conversation_id', $recipient->conversation_id)
                    ->where('direction', 'inbound')
                    ->where('created_at', '>', $sentAt)
                    ->exists()
                : false;

            $hasConversion = $recipient->contact_id
                ? Order::query()
                    ->where('tenant_id', $campaign->tenant_id)
                    ->where('contact_id', $recipient->contact_id)
                    ->where('created_at', '>', $sentAt)
                    ->exists()
                : false;

            if ($hasReply) {
                $replied++;
                if (! $recipient->replied_at) {
                    $recipient->update(['replied_at' => now(), 'status' => 'replied']);
                }
            }
            if ($hasConversion) {
                $converted++;
                if (! $recipient->converted_at) {
                    $recipient->update(['converted_at' => now(), 'status' => 'converted']);
                }
            }
        }

        $campaign->update([
            'replied_count' => $replied,
            'converted_count' => $converted,
        ]);
    }

    private function nextRunAt(string $frequency): \Carbon\Carbon
    {
        return match ($frequency) {
            'weekly' => now()->addWeek(),
            default => now()->addDay(),
        };
    }
}
