<?php


namespace WPIS;

use WPIS\ImmosyncClient;

class FormManager
{

    private $errors = [];
    private $payload = [];
    private $formdata = [];

    private $contactSavingEnabled = true;
    private $emailRecipientEnabled = true;
    private $emailClientEnabled = true;
    private $emailDefaultSender;
    private $emailDefaultSenderName;
    private $emailDefaultReceiver;

    static public function init()
    {
        $class = new self();

        DatabaseManager::createContactTable();

        $class->contactSavingEnabled = SettingsManager::get('formEnableContactSaving');
        $class->emailRecipientEnabled = SettingsManager::get('formEnableRecipientEmail');
        $class->emailClientEnabled = SettingsManager::get('formEnableClientEmail');
        $class->emailDefaultSender = SettingsManager::get('formEmailDefaultSender') ?? get_bloginfo('admin_email');
        $class->emailDefaultSenderName = SettingsManager::get('formEmailDefaultSenderName') ?? get_bloginfo('name');
        $class->emailDefaultReceiver = SettingsManager::get('formEmailDefaultReceiver') ?? get_bloginfo('admin_email');

        if ($class->emailRecipientEnabled || $class->emailClientEnabled) {
            add_filter('wp_mail_content_type', [$class, 'setEmailContentType']);
        }

        return $class;
    }

    public function handleFormData($payload)
    {

        $this->payload = $payload;

        $this->checkPayload();

        if (!empty($this->errors)) {
            return [
                'success' => false,
                'errors' => $this->errors
            ];
        }

        $this->createFormData();

        $contactId = null;

        if ($this->contactSavingEnabled) {
            $contactId = $this->saveContact();
        }

        $emailRecipientSent = $this->sendRecipientEmail();
        $emailNotificationSent = $this->sendClientEmail();

        $this->updateContactSoftwareId($contactId, [
            'email_recipient' => $emailRecipientSent,
            'email_notification' => $emailNotificationSent,
        ]);

        return [
            'success' => 'true',
            'flow' => [
                'emailRecipientSent' => $emailRecipientSent,
                'emailNotificationSent' => $emailNotificationSent
            ]
        ];
    }

    public function handleContactSync()
    {

        $wpdb = DatabaseManager::db();
        $table = $wpdb->prefix . WPIS::WP_TABLE_CONTACTS;

        $query = $wpdb->prepare("SELECT id, software_contact_id, form_data  FROM $table ORDER BY created_at DESC LIMIT 1");
        $contact = $wpdb->get_row($query);

        if (!empty($contact) && is_null($contact->software_contact_id)) {

            $this->formdata = json_decode($contact->form_data);

            $immoSyncDataSent = $this->sendFormDataImmoSync();

            if (! isset($immoSyncDataSent->success) || ! $immoSyncDataSent->success) {

                $this->sendFailedSyncEmail($immoSyncDataSent);

                return [
                    'success' => 'false',
                ];
            }

            $this->updateContactSoftwareId($contact->id, [
                'software_contact_id' => $immoSyncDataSent->contactId,
            ]);

            return [
                'success' => 'true',
            ];
        } else {
            return [
                'success' => 'true',
            ];
        }
    }

    private function checkPayload()
    {

        $acceptedSource = ['searchForm', 'contactForm', 'estateForm', 'evaluationForm'];
        $payload = (object) $this->payload;

        if (!isset($payload->source) || !in_array($payload->source, $acceptedSource)) {
            $this->errors[] = ['field' => 'source', 'message' => __('Source is not valid, valid source are: ', 'wpis') . implode(', ', $acceptedSource)];
            return;
        }

        if (!isset($payload->message) || $payload->message === '' || !$payload->message || strlen($payload->message) > 1000) {
            $this->errors[] = ['field' => 'message', 'message' => __('Message could not be null and should be maximum 1000 characters', 'wpis')];
            return;
        }
    }

    private function createFormData()
    {

        $payload = (object) $this->payload;

        // TODO : Update the logic
        $searchZips = [];
        foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] as $zipKey) {
            if (isset($payload->{'searchZipCode' . $zipKey}) && $payload->{'searchZipCode' . $zipKey}) {
                $searchZips[] = $payload->{'searchZipCode' . $zipKey};
            }
        }

        $gender = trim(strip_tags($payload->gender));
        $gender = $gender !== 'none' ? $gender : null;

        $input = [
            'source'    => $payload->source,
            'url'       => $payload->url,

            'firstname' => trim(strip_tags($payload->firstname)),
            'lastname'  => trim(strip_tags($payload->lastname)),
            'gender'    => $gender,
            'phone'     => trim(strip_tags($payload->phone)),
            'email'     => trim(strip_tags($payload->email)),

            'agreement' => isset($payload->agreement) && $payload->agreement,

            'addressNumber' =>  trim(strip_tags($payload->addressNumber)),
            'addressZip'    =>  trim(strip_tags($payload->addressZip)),
            'addressStreet' =>  trim(strip_tags($payload->addressStreet)),
            'addressCity'   =>  trim(strip_tags($payload->addressCity)),
            'addressBox'    =>  trim(strip_tags($payload->addressBox)),

            'message' => trim(strip_tags($payload->message))
        ];

        if ($payload->officeId) {
            $input['officeId'] = $payload->officeId;
        }

        if ($payload->source === 'searchForm') {
            $search = (object) $payload->search;
            $input['search'] = [
                'purpose'    => $search->purpose,
                'category'   => $search->category,
                'priceRange' => [$search->priceRange[0], $search->priceRange[1]],
                'rooms'      => $search->rooms,
                'areaMin'    => $search->areaMin,
                'areaMax'    => $search->areaMax,
                'zips'       => $search->zips
            ];
        }

        if ($payload->source === 'estateForm') {
            $input['estateId'] = $payload->estateId;
            $input['postId'] = $payload->postId;
            $input['listId'] = $payload->listId;
        }

        $this->formdata = $input;
    }

    private function saveContact()
    {

        $wpdb = DatabaseManager::db();
        $table = $wpdb->prefix . WPIS::WP_TABLE_CONTACTS;

        $contact = [
            'source' => $this->formdata['source'],
            'firstname' => $this->formdata['firstname'],
            'lastname' => $this->formdata['lastname'],
            'email' => $this->formdata['email'],
            'form_data' => json_encode($this->formdata),
            'email_recipient' => false,
            'email_notification' => false,
            'software_contact_id' => null
        ];

        $wpdb->insert($table, $contact);

        return $wpdb->insert_id;
    }

    private function updateContactSoftwareId($contactId, $data)
    {

        $wpdb = DatabaseManager::db();
        $table = $wpdb->prefix . WPIS::WP_TABLE_CONTACTS;

        $wpdb->update($table, $data, ['ID' => $contactId]);
    }

    public function getSavedContacts()
    {

        $wpdb = DatabaseManager::db();
        $table = $wpdb->prefix . WPIS::WP_TABLE_CONTACTS;

        $contacts = $wpdb->get_results("SELECT * FROM $table");
        $contactMapped = [];

        foreach ($contacts as $contact) {
            $contact->form_data = json_decode($contact->form_data);
            $contactMapped[] = $contact;
        }

        return [
            'success' => true,
            'data' => $contactMapped,
            'total' => count($contacts)
        ];
    }

    private function sendFormDataImmoSync()
    {
        return ImmosyncClient::init()->createContact((object) $this->formdata);
    }

    private function sendRecipientEmail()
    {

        if (! $this->emailRecipientEnabled) {
            return false;
        }

        $recipient = $this->formdata['email'];
        $headers = [
            'From: ' . $this->emailDefaultSenderName . ' <' . $this->emailDefaultSender . '>'
        ];
        $subject = '[' . get_bloginfo('name') . ']' . ' Nous avons bien reçu votre message';
        $headline = 'Bonjour ' . $this->formdata['firstname'];
        $signature = 'L\'équipe de ' . get_bloginfo('name');
        $footer = 'Ceci est un message automatique envoyé via ImmoSync';
        $message = $this->parseEmailContent('recipient-email.html', $this->getEmailContentValues());

        $body = $this->renderEmailLayout($headline, $message, $signature, $footer);

        return wp_mail($recipient, $subject, $body, $headers);
    }

    private function sendClientEmail()
    {
        if (! $this->emailClientEnabled) {
            return false;
        }

        $recipient = $this->emailDefaultReceiver;
        $headers = [
            'From: ' . $this->emailDefaultSenderName . ' <' . $this->emailDefaultSender . '>'
        ];
        $subject = '[WP Immo Sync]' . ' Nouveau message reçu';
        $headline = 'Bonjour';
        $signature = 'Formulaire ' . get_bloginfo('name');
        $footer = 'Ceci est un message automatique envoyé via ImmoSync';
        $message = $this->parseEmailContent('client-email.html', $this->getEmailContentValues());

        $body = $this->renderEmailLayout($headline, $message, $signature, $footer);

        return wp_mail($recipient, $subject, $body, $headers);
    }

    private function sendFailedSyncEmail($errorImmoSyncData)
    {

        $headers = [
            'From: ' . $this->emailDefaultSenderName . ' <' . $this->emailDefaultSender . '>'
        ];
        $recipients = [WPIS::EMAIL_CONTACT_FAILURE, get_bloginfo('admin_email')];
        $this->formdata = (array) $this->formdata;

        $subject = '[WP Immo Sync] ' . get_bloginfo('name') . ' - Contact non synchronisé avec le logiciel';
        $headline = 'Bonjour';
        $signature = 'Systeme de synchronisation ImmoSync de ' . get_bloginfo('name');
        $footer = 'Ceci est un message automatique envoyé via ImmoSync';
        $message = $this->parseEmailContent('failed-sync-email.html', $this->getEmailContentValues([
            'errorMessage' => json_encode($errorImmoSyncData),
        ]));

        $body = $this->renderEmailLayout($headline, $message, $signature, $footer);

        return wp_mail($recipients, $subject, $body, $headers);
    }

    private function getEmailContentValues(array $extra = [])
    {

        $formdata = (array) $this->formdata;
        $search = isset($formdata['search']) ? (array) $formdata['search'] : [];
        $priceRange = isset($search['priceRange']) ? (array) $search['priceRange'] : ['', ''];
        $zips = isset($search['zips']) ? (array) $search['zips'] : [];
        $source = $formdata['source'] ?? '';
        $postId = $formdata['postId'] ?? null;

        return array_merge([
            'firstname' => $formdata['firstname'] ?? '',
            'lastname' => $formdata['lastname'] ?? '',
            'email' => $formdata['email'] ?? '',
            'phone' => $formdata['phone'] ?? '',
            'message' => $formdata['message'] ?? '',
            'source' => $source,
            'url' => $formdata['url'] ?? '',
            'addressStreet' => $formdata['addressStreet'] ?? '',
            'addressNumber' => $formdata['addressNumber'] ?? '',
            'addressBox' => $formdata['addressBox'] ?? '',
            'addressZip' => $formdata['addressZip'] ?? '',
            'addressCity' => $formdata['addressCity'] ?? '',
            'searchPurpose' => $search['purpose'] ?? '',
            'searchCategory' => $search['category'] ?? '',
            'searchPriceMin' => $priceRange[0] ?? '',
            'searchPriceMax' => $priceRange[1] ?? '',
            'searchRooms' => $search['rooms'] ?? '',
            'searchAreaMin' => $search['areaMin'] ?? '',
            'searchAreaMax' => $search['areaMax'] ?? '',
            'searchZips' => implode(', ', $zips),
            'estateId' => $formdata['estateId'] ?? '',
            'estateReference' => $postId ? $this->getEstateMeta($postId, 'wpis_reference') : '',
            'estateName' => $postId ? $this->getEstateMeta($postId, 'wpis_name') : '',
            'address' => !empty($formdata['addressStreet']),
            'search' => $source === 'searchForm',
            'estate' => $source === 'estateForm',
        ], $extra);
    }

    private function parseEmailContent(string $filename, array $values): string
    {
        $pluginPath = __DIR__ . '/../templates/email/content/' . $filename;
        $themeRelativePath = $this->getThemeEmailContentPath($filename);
        $path = $themeRelativePath
            ? $this->resolveEmailTemplatePath($themeRelativePath, $pluginPath)
            : $pluginPath;

        $html = file_get_contents($path);

        $html = preg_replace_callback(
            '/\{\{#(\w+)\}\}(.*?)\{\{\/\1\}\}/s',
            function ($matches) use ($values) {
                return !empty($values[$matches[1]]) ? $matches[2] : '';
            },
            $html
        );

        foreach ($values as $key => $value) {
            if (is_bool($value) || is_array($value)) {
                continue;
            }
            $html = str_replace('{{ ' . $key . ' }}', (string) $value, $html);
        }

        return $html;
    }

    private function renderEmailLayout(string $headline, string $message, string $signature, string $footer): string
    {
        $pluginPath = __DIR__ . '/../templates/email/default.email.html';
        $path = $this->resolveEmailTemplatePath('immosync/email/template.html', $pluginPath);

        $template = file_get_contents($path);
        $template = str_replace(["\r", "\n"], '', $template);

        return str_replace(
            ['{{ email.headline }}', '{{ email.message }}', '{{ email.signature }}', '{{ email.footer }}'],
            [$headline, $message, $signature, $footer],
            $template
        );
    }

    private function getThemeEmailContentPath(string $filename): ?string
    {
        $map = [
            'client-email.html' => 'immosync/email/client-content.html',
            'recipient-email.html' => 'immosync/email/recipient-content.html',
        ];

        return $map[$filename] ?? null;
    }

    private function resolveEmailTemplatePath(string $themeRelativePath, string $pluginAbsolutePath): string
    {
        return ThemeTemplateResolver::resolve($themeRelativePath, $pluginAbsolutePath, 'wpis_email_template_path');
    }

    private function getEstateMeta($postId, $meta)
    {
        return get_post_meta($postId, $meta, true);
    }

    public function setEmailContentType()
    {
        return 'text/html';
    }
}
