<?php

namespace Tricks\CampaignMonitor;

use CS_REST_Transactional_SmartEmail;
use CS_REST_Wrapper_Result;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\LaravelData\Data;
use Tricks\CampaignMonitor\Data\ResultData;
use Tricks\CampaignMonitor\Helpers\Exceptional;
use function Sentry\captureException;
use function Sentry\captureMessage;

class CampaignMonitor
{
    public function __construct(protected CS_REST_Transactional_SmartEmail $campaignMonitorTransactional)
    {
    }

    /**
     * @param  string  $smartEmailId
     * @param  string  $smartEmailRecipient
     * @param  array  $messageData
     * @param  array  $attachments
     * @return CS_REST_Wrapper_Result
     */
    public function sendTransactional(
        string $smartEmailId,
        string $smartEmailRecipient,
        array $messageData,
        array $attachments = []
    ): CS_REST_Wrapper_Result {

        $this->campaignMonitorTransactional->set_smartemail_id($smartEmailId);

        $to = explode(';', $smartEmailRecipient);
        $to = array_map('trim', $to);

        $simpleMessage = [
            "To" => $to,
            "Data" => $messageData,
        ];

        if (! empty($attachments)) {
            $simpleMessage['Attachments'] = $attachments;
        }

        $consentToTrack = 'no'; # Valid: 'yes', 'no', 'unchanged'

        return $this->campaignMonitorTransactional->send($simpleMessage, $consentToTrack);
    }

    /**
     * @throws Exception
     */
    public function send(string $transaction, Data $data, ?string $recipient = null): true|ResultData
    {
        try {
            $smartEmailId = Exceptional::config('campaignmonitor.transactional.mails.'.$transaction.'.id');

            $recipient = $recipient
                ?? config('campaignmonitor.transactional.mails.'.$transaction.'.recipient')
                ?? throw new Exception('Missing recipient.');

            $attachments = [];
            if (isset($data->attachments)) {
                $attachments = $data->attachments;
            }

            $result = $this->sendTransactional($smartEmailId, $recipient, $data->toArray(), $attachments);

            $response = json_encode($result->response);
            if (! $result->was_successful()) {
                $this->captureMessage(
                    'Failed to send transactional. Request was not successful.',
                    $transaction,
                    $result,
                    $data,
                    $recipient
                );
                return new ResultData(
                    code: $result->http_status_code,
                    campaign_monitor_error: $response,
                );
            }
            if (Str::contains($response, 'Accepted')) {
                return true;
            }
            $this->captureMessage(
                'Failed to send transactional. Successful response does not contain "Accepted".',
                $transaction,
                $result,
                $data,
                $recipient
            );

            return new ResultData(
                code: $result->http_status_code,
                response: $response,
            );
        } catch (Exception $exception) {
            Log::critical('Failed to send transactional', [
                'transactional' => $transaction,
                'code' => $exception->getCode(),
                'message' => $exception->getMessage(),
                'data' => $data->toArray(),
                'trace' => $exception->getTraceAsString(),
                'recipient' => $recipient,
            ]);
            captureException($exception);
            return new ResultData(
                code: $exception->getCode(),
                laravel_error: $exception->getMessage(),
            );
        }
    }

    private function captureMessage(
        string $message,
        string $transaction,
        CS_REST_Wrapper_Result $result,
        Data $data,
        string $recipient
    ): void {

        Log::error($message, [
            'transactional' => $transaction,
            'code' => $result->http_status_code,
            'response' => $result->response,
            'data' => $data->toArray(),
            'recipient' => $recipient,
        ]);
        captureMessage($message);
    }
}
