<?php

namespace App\Crm;

use App\Facades\Settings;
use App\Traits\LoadsDataFromSource;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Mtc\Crm\Contracts\EnquiryActionModel;
use Mtc\Crm\Contracts\EnquiryModel;
use Mtc\MercuryDataModels\Dealership;

class SendCopyViaMail extends \Mtc\Crm\Actions\SendCopyViaMail
{
    use LoadsDataFromSource;
    use CheckForExpiredAction;

    private string $error;

    private array $recipients = [];

    public function enabled(): bool
    {
        return true;
    }

    /**
     * Data fields to add to form
     *
     * @return array
     */
    public function formAdditionalDataFields(): array
    {
        return [
            'send_to_field_location' => [
                'type' => 'text',
                'validation' => [
                    'required',
                    'email',
                ],
                'label' => 'Name of question that specifies to where to send submission'
            ],
            'send_to_both' => [
                'type' => 'checkbox',
                'validation' => [
                ],
                'label' => 'Send to both custom email field and action email'
            ],
            'recipient' => [
                'type' => 'text',
                'validation' => [
                    'required',
                    'email',
                ],
                'label' => 'Send Email To'
            ],
            'enquiry_subject' => [
                'type' => 'text',
                'validation' => 'required',
                'label' => 'Enquiry Email Subject',
            ],
            'enquiry_content' => [
                'type' => 'textarea',
                'label' => 'Enquiry Email Message',
            ],
        ];
    }

    /**
     * Handle the action
     *
     * @param EnquiryActionModel $action
     * @param EnquiryModel $enquiry
     * @return bool
     */
    public function handle(EnquiryActionModel $action, EnquiryModel $enquiry): ?bool
    {
        if ($this->expired($action)) {
            return null;
        }

        // Clone the enquiry to leave the original intact
        $clonedEnquiry = clone $enquiry;
        $clonedEnquiry->details = $this->adjustEnquiryDetails($enquiry);

        try {
            $this->action = $action;
            $emails = $this->determineRecipients($clonedEnquiry, $action);
            $this->recipients = $emails;
            if (!empty($emails)) {
                $class = config('crm.new_enquiry_email');
                collect($emails)->each(fn($email) => Mail::to($email)->send(new $class($clonedEnquiry)));
                return true;
            }
        } catch (\Exception $exception) {
            $this->error = $exception->getMessage();
            Log::error($exception->getMessage(), [
                'tenant' => tenant('id'),
                'emails' => $emails,
                'exception' => $exception,
            ]);
        }
        return false;
    }

    public function successDetails(): string
    {
        return "Copy sent to " . implode(', ', $this->recipients);
    }

    public function failureReason(): string
    {
        if (empty($this->recipients)) {
            return 'no recipient specified';
        }
        return $this->error ?? 'issue sending mail';
    }

    private function adjustEnquiryDetails(EnquiryModel $enquiry): array
    {
        $details = collect($enquiry->details)->map(fn($detail) => (array) $detail)->toArray();

        foreach ($details as $key => $detail) {
            $details[$key]['question'] = strip_tags($details[$key]['question']);
            $question = $enquiry
                ->form
                ->questionsInclTrashed->where('id', $detail['id'])
                ->first();

            // Answer is an ID of a data source
            $source = $question?->data['meta']['options']['source'] ?? null;
            if (!empty($source) && is_numeric($detail['answer'])) {
                $details[$key]['original_answer'] = $detail['answer'];
                $details[$key]['answer'] = $this->getChoicesFromDataSource($source)
                    ->filter(fn($row) => $row->id == $detail['answer'])
                    ->first()
                    ?->name ?? __('labels.unknown');
            }

            // If question is "Select Branch" or "Dealer", rename + look up dealership
            if (in_array($detail['question'], ['Select Branch', 'Dealership']) && is_numeric($detail['answer'])) {
                $dealership = Dealership::query()->find((int)$detail['answer']);
                if (!empty($dealership)) {
                    $details[$key]['question'] = 'Dealership';
                    $details[$key]['original_answer'] = $detail['answer'];
                    $details[$key]['answer'] = $dealership->name;
                }
            }
        }

        return $details;
    }

    private function determineRecipients(EnquiryModel $enquiry, EnquiryActionModel $action): array
    {
        $sendToBoth = $action->data['send_to_both'] ?? false;
        $emails = $this->emailsSpecifiedByQuestions($enquiry);

        if ($this->action->data['send_to_field_location'] ?? null) {
            $emails = $this->emailsSpecifiedInLocationField($emails, $enquiry);
        }

        if ($sendToBoth || empty($emails)) {
            $emails = array_merge($emails, $this->emailsSpecifiedInMainField());
        }

        $emails = array_merge(
            $emails,
            $this->enquiryVehicleRecipients($enquiry),
        );

        return array_unique($emails);
    }

    private function enquiryVehicleRecipients(EnquiryModel $enquiry): array
    {
        $enquiry_vehicles = $enquiry->objects->filter(fn ($object) => $object->object_type === 'vehicle');

        return $enquiry_vehicles->count() && Settings::get('form-enquiry-send-to-vehicle-dealership')
            ? explode(',', $enquiry_vehicles->first()?->object?->dealership?->email ?? '')
            : [];
    }

    private function emailsSpecifiedInLocationField(array $emails, EnquiryModel $enquiry): array
    {
        $specifiedField = $this->action->data['send_to_field_location'] ?? null;

        $emails[] = collect($enquiry->details ?? [])
            ->filter(fn($answer) => $answer['question'] === $specifiedField)
            ->first()['answer'] ?? null;

        return array_filter($emails, fn($email) => $email && filter_var($email, FILTER_VALIDATE_EMAIL));
    }

    /**
     * Extracts and validates email addresses specified in the main field.
     *
     * @return array Returns an array of valid email addresses.
     */
    private function emailsSpecifiedInMainField(): array
    {
        $actionRecipient = $this->action->data['recipient'] ?? null;

        if (empty($actionRecipient)) {
            return [];
        }

        $emails = array_map('trim', explode(',', $actionRecipient));

        $validEmails = array_filter($emails, fn($email) => filter_var($email, FILTER_VALIDATE_EMAIL));

        return $validEmails;
    }

    private function emailsSpecifiedByQuestions(EnquiryModel $enquiry): array
    {
        $questionsSpecifyField = $enquiry->form->questions
            ->filter(fn($question) => $question->data['specifies-recipient'] ?? false)
            ->keyBy('id');

        if ($questionsSpecifyField->isEmpty()) {
            return [];
        }

        $questionsSpecifyFieldIds = $questionsSpecifyField->pluck('id')->toArray();
        return collect($enquiry->details ?? [])
            ->filter(fn($answer) => in_array($answer['id'], $questionsSpecifyFieldIds))
            ->map(fn($answer) => $this->extractEmailsFromAnswerValue($answer, $questionsSpecifyField))
            ->flatten(1)
            ->filter()
            ->toArray();
    }

    private function extractEmailsFromAnswerValue(array $answer, Collection $fieldMap): array
    {
        $specifiedValue = collect(explode("\n", $fieldMap[$answer['id']]->data['field-emails-specification'] ?? ''))
            ->map(fn($row) => explode(':', $row))
            ->filter(fn ($row) => array_key_exists('original_answer', $answer)
                    ? $row[0] == $answer['original_answer']
                    : $row[0] == $answer['answer'])
            ->map(fn($row) => $row[1])
            ->first();

        return collect(explode(',', $specifiedValue))
            ->map(fn($email) => trim($email))
            ->filter(fn($email) => filter_var($email, FILTER_VALIDATE_EMAIL))
            ->toArray();
    }
}
