<?php

require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'configbeez/config_email_engine.php');

class EspEventProcessor
{
    public static function process($eventId)
    {
        $event = EspEventRepository::loadById($eventId);
        if (!$event) {
            return false;
        }
        try {
            $resolved = self::resolveCorrelation($event);
            self::applyMessageState($event, $resolved);
            self::applyCompatibilitySideEffects($event, $resolved);
            EspEventRepository::markProcessed($eventId);
            return true;
        } catch (Exception $e) {
            EspEventRepository::markFailed($eventId, $e->getMessage());
            return false;
        }
    }

    private static function resolveCorrelation(array $event)
    {
        $mailbeezMessageId = self::firstNotEmpty(array(
            self::value($event, 'mailbeez_message_id'),
            self::valuePath($event, 'raw_payload.headers.X-MailBeez-Message-ID'),
            self::valuePath($event, 'raw_payload.tags.mailbeez_message_id'),
        ));

        $confidence = 'none';
        if ($mailbeezMessageId) {
            $confidence = 'strong';
        }

        if (!$mailbeezMessageId && self::value($event, 'provider_message_id')) {
            $mailbeezMessageId = EspEventRepository::findMailbeezMessageIdByProviderMessage(
                self::value($event, 'provider'),
                self::value($event, 'provider_message_id')
            );
            if ($mailbeezMessageId) {
                $confidence = 'strong';
            }
        }

        $autoemailId = null;
        if ($mailbeezMessageId) {
            $sql = "select autoemail_id from " . TABLE_MAILBEEZ_TRACKING . " where message_id='" . mh_db_input((string)$mailbeezMessageId) . "' order by autoemail_id desc limit 1";
            $query = mh_db_query($sql);
            if (mh_db_num_rows($query) > 0) {
                $row = mh_db_fetch_array($query);
                $autoemailId = (int)$row['autoemail_id'];
            }
        }

        if (!$mailbeezMessageId) {
            $windowStart = date('Y-m-d H:i:s', strtotime((string)self::value($event, 'event_time') . ' -1 hour'));
            $windowEnd = date('Y-m-d H:i:s', strtotime((string)self::value($event, 'event_time') . ' +1 hour'));
            $sql = "select autoemail_id, message_id from " . TABLE_MAILBEEZ_TRACKING . "
                    where customers_email='" . mh_db_input((string)self::value($event, 'recipient_email')) . "'
                      and date_sent between '" . mh_db_input($windowStart) . "' and '" . mh_db_input($windowEnd) . "'
                    order by autoemail_id desc limit 1";
            $query = mh_db_query($sql);
            if (mh_db_num_rows($query) > 0) {
                $row = mh_db_fetch_array($query);
                $autoemailId = (int)$row['autoemail_id'];
                $mailbeezMessageId = (string)$row['message_id'];
                $confidence = 'weak';
            }
        }

        return array(
            'mailbeez_message_id' => $mailbeezMessageId,
            'autoemail_id' => $autoemailId,
            'correlation_confidence' => $confidence,
        );
    }

    private static function applyCompatibilitySideEffects(array $event, array $resolved)
    {
        $eventType = self::value($event, 'event_type', 'unknown');
        $autoemailId = self::value($resolved, 'autoemail_id');
        $customersId = self::lookupCustomersIdByAutoemail($autoemailId);

        if ($eventType === 'soft_bounce' || $eventType === 'hard_bounce') {
            if (!$customersId && self::value($resolved, 'correlation_confidence') === 'weak' && $eventType === 'hard_bounce') {
                return;
            }
            if ($customersId) {
                config_email_engine::trackBounce(array(
                    'classification' => ($eventType === 'hard_bounce') ? 'hard' : 'soft',
                    'time' => date('c', strtotime((string)self::value($event, 'event_time'))),
                    'reference' => (string)self::value($event, 'provider_event_id', ''),
                    'address' => (string)self::value($event, 'recipient_email', ''),
                ));
            }
            return;
        }

        if ($autoemailId) {
            if ($eventType === 'open') {
                mh_db_query("update " . TABLE_MAILBEEZ_TRACKING . " set opened=1 where autoemail_id='" . (int)$autoemailId . "' and opened=0");
            }
            if ($eventType === 'click') {
                mh_db_query("update " . TABLE_MAILBEEZ_TRACKING . " set clicked=1 where autoemail_id='" . (int)$autoemailId . "' and clicked=0");
            }
            if ($eventType === 'unsubscribe' || $eventType === 'complaint' || $eventType === 'hard_bounce') {
                $bounceStatus = ($eventType === 'hard_bounce' || $eventType === 'complaint') ? 'H' : 'S';
                mh_db_query("update " . TABLE_MAILBEEZ_TRACKING . " set bounce_status='" . mh_db_input($bounceStatus) . "' where autoemail_id='" . (int)$autoemailId . "'");
            }
        }
    }

    private static function applyMessageState(array $event, array $resolved)
    {
        $autoemailId = self::value($resolved, 'autoemail_id');
        if (!$autoemailId) {
            return;
        }

        $eventType = (string)self::value($event, 'event_type', 'unknown');
        $status = self::statusForEvent($eventType);
        $eventTime = (string)self::value($event, 'event_time', date('Y-m-d H:i:s'));

        $sql = "select * from " . TABLE_MAILBEEZ_ESP_MESSAGE_STATE . " where autoemail_id='" . (int)$autoemailId . "' limit 1";
        $query = mh_db_query($sql);

        if (mh_db_num_rows($query) < 1) {
            $insert = array(
                'autoemail_id' => (int)$autoemailId,
                'mailbeez_message_id' => (string)self::value($resolved, 'mailbeez_message_id', ''),
                'provider' => (string)self::value($event, 'provider', ''),
                'provider_message_id' => self::value($event, 'provider_message_id'),
                'status' => $status,
                'last_event_type' => $eventType,
                'last_event_time' => $eventTime,
                'last_reason' => self::value($event, 'reason'),
                'attempt_count' => ($eventType === 'attempt') ? 1 : 0,
                'soft_bounce_count' => ($eventType === 'soft_bounce') ? 1 : 0,
                'hard_bounce_count' => ($eventType === 'hard_bounce') ? 1 : 0,
                'complaint_count' => ($eventType === 'complaint') ? 1 : 0,
                'unsubscribe_count' => ($eventType === 'unsubscribe') ? 1 : 0,
                'open_count' => ($eventType === 'open') ? 1 : 0,
                'click_count' => ($eventType === 'click') ? 1 : 0,
                'updated_at' => date('Y-m-d H:i:s'),
            );
            mh_db_perform(TABLE_MAILBEEZ_ESP_MESSAGE_STATE, $insert);
            return;
        }

        $current = mh_db_fetch_array($query);
        $currentStatus = (string)$current['status'];
        if (self::isTerminalStatus($currentStatus) && !self::isTerminalStatus($status)) {
            $status = $currentStatus;
        }

        $update = array(
            'status' => $status,
            'last_event_type' => $eventType,
            'last_event_time' => $eventTime,
            'last_reason' => self::value($event, 'reason'),
            'attempt_count' => (int)$current['attempt_count'] + (($eventType === 'attempt') ? 1 : 0),
            'soft_bounce_count' => (int)$current['soft_bounce_count'] + (($eventType === 'soft_bounce') ? 1 : 0),
            'hard_bounce_count' => (int)$current['hard_bounce_count'] + (($eventType === 'hard_bounce') ? 1 : 0),
            'complaint_count' => (int)$current['complaint_count'] + (($eventType === 'complaint') ? 1 : 0),
            'unsubscribe_count' => (int)$current['unsubscribe_count'] + (($eventType === 'unsubscribe') ? 1 : 0),
            'open_count' => (int)$current['open_count'] + (($eventType === 'open') ? 1 : 0),
            'click_count' => (int)$current['click_count'] + (($eventType === 'click') ? 1 : 0),
            'updated_at' => date('Y-m-d H:i:s'),
        );

        mh_db_perform(TABLE_MAILBEEZ_ESP_MESSAGE_STATE, $update, 'update', "autoemail_id='" . (int)$autoemailId . "'");
    }

    private static function statusForEvent($eventType)
    {
        switch ($eventType) {
            case 'queued':
                return 'queued';
            case 'attempt':
                return 'attempting';
            case 'sent':
                return 'sent';
            case 'open':
            case 'click':
                return 'engaged';
            case 'soft_bounce':
                return 'soft_failed';
            case 'hard_bounce':
                return 'hard_failed';
            case 'complaint':
                return 'suppressed';
            case 'unsubscribe':
                return 'suppressed';
            default:
                return 'unknown';
        }
    }

    private static function isTerminalStatus($status)
    {
        return in_array((string)$status, array('hard_failed', 'suppressed', 'complaint', 'unsubscribe'), true);
    }

    private static function lookupCustomersIdByAutoemail($autoemailId)
    {
        if (!$autoemailId) {
            return null;
        }
        $sql = "select customers_id from " . TABLE_MAILBEEZ_TRACKING . " where autoemail_id='" . (int)$autoemailId . "' limit 1";
        $query = mh_db_query($sql);
        if (mh_db_num_rows($query) > 0) {
            $row = mh_db_fetch_array($query);
            return (int)$row['customers_id'];
        }
        return null;
    }

    private static function firstNotEmpty(array $values)
    {
        foreach ($values as $value) {
            if ($value !== null && $value !== '') {
                return $value;
            }
        }
        return null;
    }

    private static function value(array $array, $key, $fallback = null)
    {
        return array_key_exists($key, $array) ? $array[$key] : $fallback;
    }

    private static function valuePath(array $array, $path)
    {
        $segments = explode('.', $path);
        $value = $array;
        foreach ($segments as $segment) {
            if (!is_array($value) || !array_key_exists($segment, $value)) {
                return null;
            }
            $value = $value[$segment];
        }
        return $value;
    }
}
