<?php

namespace WPDesk\Library\WPEmail;

use Exception;
use WP_Error;
use WPDesk\Library\WPEmail\Abstracts\Email;
use WPDesk\Library\WPEmail\Abstracts\Mailer;
use WPDesk\Library\WPEmail\Exceptions\MailerException;
use WPDesk\View\Renderer\Renderer;
use WPDesk\View\Renderer\SimplePhpRenderer;
use WPDesk\View\Resolver\ChainResolver;
use WPDesk\View\Resolver\DirResolver;


class WPMailer implements Mailer {

    /**
     * @var Renderer
     */
    private $renderer;

    public function __construct() {
        $resolver = new ChainResolver();
        $resolver->appendResolver( new DirResolver( __DIR__ . '/templates' ) );
        $renderer = new SimplePhpRenderer( $resolver );
        $this->set_renderer( $renderer );
    }

    public function set_renderer( Renderer $renderer ) {
        $this->renderer = $renderer;
    }

    public function get_renderer(): Renderer {
        return $this->renderer;
    }

    /** @return void */
    public function send( Email $email ): void {
        $mailer_from = $email->get_from();
        add_filter(
            'wp_mail_from',
            $from_cb = static function ( $from ) use ( $mailer_from ) {
                return $mailer_from;
            }
        );

        $mailer_from_name = $email->get_from_name();
        add_filter(
            'wp_mail_from_name',
            $from_name_cb = static function ( $from_name ) use ( $mailer_from_name ) {
                return $mailer_from_name;
            }
        );
        add_action( 'wp_mail_failed', [ $this, 'catch_error' ] );

        $email_template = new EmailTemplate( $this->renderer, $email->get_template_attributes() );

        try {
            $success = wp_mail(
                $email->get_recipients(),
                $email->get_subject(),
                $email_template->get_email_template( $email->get_content() ),
                $email->get_headers(),
                $email->get_attachments()
            );
            if ( ! $success ) {
                throw new MailerException( 'Count not send the mail with wp_mail()' );
            }
        } catch ( Exception $e ) {
            if ( $e instanceof MailerException ) {
                throw $e;
            }

            throw new MailerException( sprintf( 'wp_mail() failure. Original error: %s', $e->getMessage() ), 0, $e );
        } finally {
            remove_action( 'wp_mail_failed', [ $this, 'catch_error' ], 99999 );
            remove_filter( 'wp_mail_from', $from_cb );
            remove_filter( 'wp_mail_from_name', $from_name_cb );
        }
    }

    /** @return void */
    public function catch_error( WP_Error $error ) {
        throw MailerException::with_wp_error( $error );
    }

}