<?php

namespace WPDesk\Library\WPEmail;

use Exception;
use WP_Error;
use WPDesk\Library\WPEmail\Abstracts\EmailInterface;
use WPDesk\Library\WPEmail\Helpers\HTML;
use WPDesk\View\Renderer\Renderer;
use WPDesk\View\Renderer\SimplePhpRenderer;
use WPDesk\View\Resolver\ChainResolver;
use WPDesk\View\Resolver\DirResolver;

class Mailer {

    /**
     * @var EmailInterface[]
     */
    private $emails = [];

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

    /**
     * @param array $dirs
     */
    public function __construct(
        array $dirs = []
    ) {
        $this->set_renderer( $this->init_renderer( $dirs ) );
    }

    /**
     * @param array $dirs
     *
     * @return Renderer
     */
    private function init_renderer( array $dirs = [] ): Renderer {
        $resolver = new ChainResolver();
        foreach ( $dirs as $dir ) {
            $resolver->appendResolver( new DirResolver( $dir ) );
        }
        $resolver->appendResolver( new DirResolver( __DIR__ . '/templates' ) );

        return new SimplePhpRenderer( $resolver );
    }

    /**
     * @param Renderer $renderer
     *
     * @return void
     */
    public function set_renderer( Renderer $renderer ) {
        $this->renderer = $renderer;
    }

    /**
     * @param EmailInterface $email
     *
     * @return void
     */
    public function add_email( EmailInterface $email ) {
        $this->emails[ $email->get_id() ] = $email;
    }

    /**
     * @return EmailInterface[]
     */
    public function get_emails(): array {
        return $this->emails;
    }

    /** @return void */
    public function send() {
        foreach ( $this->get_emails() as $email ) {
            add_filter(
                'wp_mail_from',
                $from_cb = static function () use ( $email ) {
                    return $email->get_from();
                }
            );
            add_filter(
                'wp_mail_from_name',
                $from_name_cb = static function () use ( $email ) {
                    return $email->get_from_name();
                }
            );
            add_action( 'wp_mail_failed', [ $this, 'catch_error' ] );

            try {
                $success = wp_mail(
                    $email->get_recipients(),
                    $email->get_subject(),
                    $this->get_email_template( $email ),
                    $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 );
    }

    protected function get_email_template( EmailInterface $email ): string {
        $output = $this->renderer->render( 'html/email-header', [ 'heading' => $email->get_heading(), 'logo' => '' ] );
        $output .= $this->renderer->render( 'html/' . $email->get_id(), [ 'content' => $email->get_content() ] );
        $output .= $this->renderer->render( 'html/email-footer', [ 'footer' => '' ] );

        return $this->css_inline( $output );
    }

    /**
     * @param string $content
     *
     * @return mixed|string
     */
    protected function css_inline( string $content ): string {
        $styles = $this->renderer->render( 'html/email-styles', [] );

        return HTML::style_inline( $content, $styles );
    }


}