<?php

namespace App\Modules\EmailShip\Infraestructure;

use App\Modules\EmailShip\Application\EmailShipInserter;
use App\Modules\EmailShip\Application\EmailShipUpdater;
use App\Modules\EmailShip\Domain\EmailCollection;
use App\Modules\EmailShip\Domain\EmailShipBcc;
use App\Modules\EmailShip\Domain\EmailShipResponse;
use App\Modules\EmailShip\Domain\EmailShipShippedRepository;
use App\Modules\EmailShip\Domain\EmailShipStatus;
use App\Modules\EmailShip\Domain\EmailShipTo;
use App\Modules\EmailShip\Domain\IdEmailShip;
use App\Modules\EmailShip\Domain\InsertEmailShip;
use App\Modules\EmailShip\Domain\UpdateEmailShip;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail;
use Throwable;

class MysqlEmailShipShippedRepository implements EmailShipShippedRepository
{

    public function ship(
        EmailCollection $email,
        EmailCollection $bcc,
        EmailCollection $replyTo,
        Mailable $mail,
        EmailShipInserter $inserter,
        EmailShipUpdater $updater
    ) {
        $idEmailShip = $this->insertEmailShip($inserter, $email, $bcc);
        try {
            $response = Mail::to($email->getMailData());
            if (count($bcc)) {
                $response->bcc($bcc->getMailData());
            }
            $response->send($mail);
            $this->updateSuccessfulEmailShip($updater, $idEmailShip);
        } catch (Throwable $th) {
            $this->updateErrorEmailShip($updater, $idEmailShip, $th);
            throw $th;
        }
        return $response;
    }

    private function insertEmailShip(
        EmailShipInserter $inserter,
        EmailCollection $email,
        EmailCollection $bcc
    ):IdEmailShip {
        $inserted = $inserter->__invoke(new InsertEmailShip(
            new EmailShipTo($email->getMails()),
            new EmailShipBcc($bcc->getMails()),
            new EmailShipStatus(EmailShipStatus::PENDING)
        ));
        return new IdEmailShip($inserted['Response_Data']['Id']);
    }

    private function updateSuccessfulEmailShip(EmailShipUpdater $updater, IdEmailShip $idEmailShip)
    {
        return $updater->__invoke(
            new UpdateEmailShip(
                $idEmailShip,
                new EmailShipResponse(EmailShipResponse::SUCCESS_MESSAGE),
                new EmailShipStatus(EmailShipStatus::SENT)
            )
        );
    }

    private function updateErrorEmailShip(EmailShipUpdater $updater, IdEmailShip $idEmailShip, Throwable $th)
    {
        return $updater->__invoke(
            new UpdateEmailShip(
                $idEmailShip,
                new EmailShipResponse(substr($th->getMessage(), 0, 1500)),
                new EmailShipStatus(EmailShipStatus::ERROR)
            )
        );
    }
}
