<?php defined('BASEPATH') or exit('No direct script access allowed');

class Postmaster extends MY_Controller
{
    public function __construct()
    {
        $this->requireAuth = false;
        parent::__construct();
        $this->load->model('items_model');
    }

    public function leads()
    {
        require_once(MODULES_PATH . 'mailbox/libraries/Imap_zisco.php');
        if (!function_exists('imap_open')) {
            return $this->postmasterOutput('PHP IMAP extension is not enabled on this server.', 500);
        }

        $host = trim((string) config_item('config_host'));
        $username = trim((string) config_item('config_username'));
        $password = decrypt(config_item('config_password'));
        $mailbox = trim((string) config_item('config_mailbox'));
        $encryption = config_item('encryption');

        if ($host === '' || $username === '' || $password === '') {
            return $this->postmasterOutput('Lead email integration is not configured.', 500);
        }

        if ($mailbox === '') {
            $mailbox = 'INBOX';
        }

        $imap = new Imap_zisco($host, $username, $password, $encryption);
        if ($imap->isConnected() === false) {
            return $this->postmasterOutput($imap->getError() ?: lang('connection_error'), 500);
        }

        $imap->selectFolder($mailbox);
        $messages = config_item('unread_email') === 'on'
            ? $imap->getUnreadMessages(true)
            : $imap->getMessages(true);

        $imported = 0;
        $skipped = 0;
        foreach ($messages as $message) {
            if (!$this->messageMatchesLeadSearch($message)) {
                $skipped++;
                continue;
            }

            if ($this->importLeadMessage($message)) {
                $imported++;
                if (config_item('delete_mail_after_import') === 'on') {
                    $imap->deleteMessage($message['uid']);
                }
            } else {
                $skipped++;
            }
        }

        $imap->close();
        $this->saveConfig('last_postmaster_run', time());

        return $this->postmasterOutput("Lead postmaster finished. Imported: {$imported}. Skipped: {$skipped}.");
    }

    private function messageMatchesLeadSearch(array $message): bool
    {
        if (config_item('imap_search_for_leads') !== 'on') {
            return true;
        }

        $keyword = trim((string) config_item('leads_keyword'));
        if ($keyword === '') {
            return true;
        }

        $haystack = implode(' ', array(
            $message['subject'] ?? '',
            $message['from'] ?? '',
            $message['body'] ?? '',
        ));

        return stripos($haystack, $keyword) !== false;
    }

    private function importLeadMessage(array $message): bool
    {
        $uid = (string) ($message['uid'] ?? '');
        if ($uid === '' || total_rows('tbl_leads', array('email_integration_uid' => $uid)) > 0) {
            return false;
        }

        $sender = $this->parseAddress((string) ($message['from'] ?? ''));
        $subject = trim((string) ($message['subject'] ?? ''));
        $body = trim(strip_tags((string) ($message['body'] ?? '')));
        $leadName = $subject !== '' ? $subject : ($sender['name'] !== '' ? $sender['name'] : $sender['email']);

        if ($leadName === '' && $sender['email'] === '') {
            return false;
        }

        $data = array(
            'lead_name' => $this->limitText($leadName, 50),
            'client_id' => 0,
            'lead_status_id' => $this->defaultLeadStatus(),
            'lead_source_id' => $this->defaultLeadSource(),
            'imported_from_email' => 1,
            'email_integration_uid' => $uid,
            'contact_name' => $this->limitText($sender['name'], 255),
            'email' => $this->limitText($sender['email'], 255),
            'notes' => $body,
            'created_time' => date('Y-m-d H:i:s'),
            'last_contact' => null,
            'permission' => $this->defaultLeadPermission(),
        );

        $this->items_model->_table_name = 'tbl_leads';
        $this->items_model->_primary_key = 'leads_id';
        $leadId = $this->items_model->save($data);
        if (empty($leadId)) {
            return false;
        }

        $this->items_model->save(array('index_no' => $leadId), $leadId);
        $this->recordLeadActivity($leadId, $data['lead_name']);
        $this->notifyLeadUsers($leadId, $data['lead_name']);

        return true;
    }

    private function parseAddress(string $address): array
    {
        if (preg_match('/^(.*?)\s*<([^>]+)>$/', $address, $matches)) {
            return array(
                'name' => trim($matches[1], " \t\n\r\0\x0B\"'"),
                'email' => trim($matches[2]),
            );
        }

        return array(
            'name' => '',
            'email' => filter_var($address, FILTER_VALIDATE_EMAIL) ? $address : '',
        );
    }

    private function defaultLeadStatus(): int
    {
        $statusId = (int) config_item('default_lead_status');
        if ($statusId > 0) {
            return $statusId;
        }

        $row = $this->db->order_by('order_no', 'ASC')->get('tbl_lead_status')->row();
        return !empty($row->lead_status_id) ? (int) $row->lead_status_id : 0;
    }

    private function defaultLeadSource(): int
    {
        $sourceId = (int) config_item('default_leads_source');
        if ($sourceId > 0) {
            return $sourceId;
        }

        $row = $this->db->order_by('lead_source_id', 'ASC')->get('tbl_lead_source')->row();
        return !empty($row->lead_source_id) ? (int) $row->lead_source_id : 0;
    }

    private function defaultLeadPermission(): string
    {
        $permission = config_item('default_lead_permission');
        return !empty($permission) ? (string) $permission : 'all';
    }

    private function recordLeadActivity(int $leadId, string $leadName): void
    {
        $activity = array(
            'user' => 0,
            'module' => 'leads',
            'module_field_id' => $leadId,
            'activity' => 'activity_save_leads',
            'icon' => 'fa-envelope',
            'link' => 'admin/leads/leads_details/' . $leadId,
            'value1' => $leadName,
        );

        $this->items_model->_table_name = 'tbl_activities';
        $this->items_model->_primary_key = 'activities_id';
        $this->items_model->save($activity);
    }

    private function notifyLeadUsers(int $leadId, string $leadName): void
    {
        $users = json_decode(config_item('notified_user'), true);
        if (empty($users) || !is_array($users)) {
            return;
        }

        foreach ($users as $userId) {
            if (empty($userId)) {
                continue;
            }
            add_notification(array(
                'to_user_id' => $userId,
                'from_user_id' => true,
                'description' => 'not_save_leads',
                'link' => 'admin/leads/leads_details/' . $leadId,
                'value' => lang('lead') . ' ' . $leadName,
            ));
        }
    }

    private function saveConfig(string $key, $value): void
    {
        $this->db->where('config_key', $key)->update('tbl_config', array('value' => $value));
        if ($this->db->affected_rows() === 0 && total_rows('tbl_config', array('config_key' => $key)) === 0) {
            $this->db->insert('tbl_config', array('config_key' => $key, 'value' => $value));
        }
        $this->cache->delete('app_config_data');
    }

    private function limitText(string $value, int $length): string
    {
        if (function_exists('mb_substr')) {
            return mb_substr($value, 0, $length);
        }
        return substr($value, 0, $length);
    }

    private function postmasterOutput(string $message, int $status = 200)
    {
        $this->output
            ->set_status_header($status)
            ->set_content_type('text/plain')
            ->set_output($message);
    }
}
