<?php

namespace BitApps\PiPro\src\Integrations\MailerPress;

use BitApps\Pi\src\Flow\NodeInfoProvider;
use MailerPress\Core\Kernel;
use MailerPress\Models\Contacts;
use WP_REST_Request;

if (!\defined('ABSPATH')) {
    exit;
}

class MailerPressServices
{
    private $nodeInfoProvider;

    public function __construct(NodeInfoProvider $nodeInfoProvider)
    {
        $this->nodeInfoProvider = $nodeInfoProvider;
    }

    public function createOrUpdateContact()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email' => ['required', 'email'],
        ];

        if ($errors = MailerPressHelper::validateFieldMap($fields, $rules)) {
            return $errors;
        }

        $email = sanitize_email($fields['email']);
        $contactData = [
            'contactEmail'        => $email,
            'contactFirstName'    => isset($fields['first_name']) ? sanitize_text_field($fields['first_name']) : '',
            'contactLastName'     => isset($fields['last_name']) ? sanitize_text_field($fields['last_name']) : '',
            'contactStatus'       => isset($fields['status']) ? sanitize_text_field($fields['status']) : 'subscribed',
            'subscription_status' => isset($fields['status']) ? sanitize_text_field($fields['status']) : 'subscribed',
            'opt_in_source'       => 'manual',
            'tags'                => MailerPressHelper::processTagsOrLists($fields['tags'] ?? []),
            'lists'               => MailerPressHelper::processTagsOrLists($fields['lists'] ?? [])
        ];

        if (\function_exists('add_mailerpress_contact')) {
            $result = add_mailerpress_contact($contactData);

            if (!isset($result['success']) || !$result['success']) {
                return [
                    'response'    => $result,
                    'payload'     => $contactData,
                    'status_code' => 500,
                ];
            }

            $contact = MailerPressHelper::getContactData($email);

            if ($contact) {
                $contactId = $contact['contact_id'] ?? 0;
                $isUpdate = $result['update'] ?? 0;

                if ($isUpdate && $contactId) {
                    do_action('mailerpress_contact_updated', $contactId);
                }

                $response = $isUpdate ? __('Contact updated successfully.', 'bit-pi') : __('Contact created successfully.', 'bit-pi');

                return [
                    'response'    => $response,
                    'payload'     => $contactData,
                    'status_code' => 200,
                ];
            }
        }

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_contact';

        $existingContact = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT contact_id FROM {$tableName} WHERE email = %s",
                $email
            )
        );

        $isUpdate = false;
        $contactId = 0;
        $requestParams = [
            'first_name'          => $contactData['contactFirstName'],
            'last_name'           => $contactData['contactLastName'],
            'subscription_status' => $contactData['contactStatus'],
            'opt_in_source'       => $contactData['opt_in_source'],
            'updated_at'          => current_time('mysql'),
        ];

        if ($existingContact) {
            $isUpdate = true;
            $contactId = $existingContact->contact_id;

            $wpdb->update(
                $tableName,
                $requestParams,
                ['contact_id' => $contactId],
                ['%s', '%s', '%s', '%s', '%s'],
                ['%d']
            );
        } else {
            $wpdb->insert(
                $tableName,
                array_merge(
                    $requestParams,
                    ['updated_at' => current_time('mysql')]
                ),
                ['%s', '%s', '%s', '%s', '%s', '%s', '%s']
            );
            $contactId = $wpdb->insert_id;
        }

        if (empty($contactId)) {
            return [
                'response'    => __('Failed to create contact.', 'bit-pi'),
                'payload'     => $contactData,
                'status_code' => 500,
            ];
        }

        $hook = $isUpdate ? 'mailerpress_contact_updated' : 'mailerpress_contact_created';
        do_action($hook, $contactId);

        $tags = $contactData['tags'] ?? [];
        $lists = $contactData['lists'] ?? [];

        if (!empty($tags)) {
            $tagsTable = $wpdb->prefix . 'mailerpress_contact_tags';

            foreach ($tags as $tag) {
                $wpdb->replace(
                    $tagsTable,
                    [
                        'contact_id' => $contactId,
                        'tag_id'     => $tag['id'],
                    ]
                );
                do_action('mailerpress_contact_tag_added', $contactId, $tag['id']);
            }
        }

        if (!empty($lists)) {
            $listsTable = $wpdb->prefix . 'mailerpress_contact_lists';

            foreach ($lists as $list) {
                $wpdb->replace(
                    $listsTable,
                    [
                        'contact_id' => $contactId,
                        'list_id'    => $list['id'],
                    ]
                );
                do_action('mailerpress_contact_list_added', $contactId, $list['id']);
            }
        }

        $responseContact = MailerPressHelper::getContactDataById($contactId);

        return [
            'response'    => $responseContact,
            'payload'     => $contactData,
            'status_code' => 200,
        ];
    }

    public function getContactByEmail()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email' => ['required', 'email'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = sanitize_email($fields['email']);

        $contact = MailerPressHelper::getContactData($email);

        return [
            'response'    => $contact ? $contact : __('Contact not found.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => $contact ? 200 : 404,
        ];
    }

    public function deleteContact()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email' => ['required', 'email'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = sanitize_email($fields['email']);
        $contact = MailerPressHelper::getContactData($email);

        if (!$contact) {
            return [
                'status_code' => 404,
                'response'    => __('Contact not found.', 'bit-pi')
            ];
        }

        $contactId = isset($contact['contact_id']) ? $contact['contact_id'] : (isset($contact['id']) ? $contact['id'] : '');

        if (empty($contactId)) {
            return [
                'status_code' => 400,
                'response'    => __('Contact ID not found.', 'bit-pi')
            ];
        }

        if (class_exists('\MailerPress\Core\Kernel')) {
            $container = Kernel::getContainer();

            if ($container && method_exists($container, 'get')) {
                $contactsModel = $container->get(Contacts::class);

                if ($contactsModel && method_exists($contactsModel, 'delete') && $contactsModel->delete($contactId)) {
                    return [
                        'status_code' => 200,
                        'payload'     => $fields,
                        'response'    => __('Contact deleted successfully.', 'bit-pi')
                    ];
                }
            }
        }

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_contact';

        $wpdb->delete(
            $wpdb->prefix . 'mailerpress_contact_tags',
            ['contact_id' => $contactId]
        );

        $wpdb->delete(
            $wpdb->prefix . 'mailerpress_contact_lists',
            ['contact_id' => $contactId]
        );

        $deleted = $wpdb->delete(
            $tableName,
            ['contact_id' => $contactId]
        );

        return [
            'response'    => $deleted ? __('Contact deleted successfully.', 'bit-pi') : __('Failed to delete contact.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => $deleted ? 200 : 500,
        ];
    }

    public function addTagToContact()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email'   => ['required', 'email'],
            'tag_ids' => ['required'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = isset($fields['email']) ? sanitize_email($fields['email']) : '';
        $contact = MailerPressHelper::getContactData($email);

        if (!$contact) {
            return [
                'response'    => __('Contact not found.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 404,
            ];
        }

        $contactId = isset($contact['contact_id']) ? $contact['contact_id'] : (isset($contact['id']) ? $contact['id'] : '');
        $tagIds = MailerPressHelper::convertStringToArray($fields['tag_ids']);

        global $wpdb;
        $tagsTable = $wpdb->prefix . 'mailerpress_contact_tags';

        foreach ($tagIds as $tagId) {
            if ($tagId > 0) {
                $wpdb->replace(
                    $tagsTable,
                    [
                        'contact_id' => $contactId,
                        'tag_id'     => $tagId,
                    ]
                );
                do_action('mailerpress_contact_tag_added', $contactId, $tagId);
            }
        }

        return [
            'response'    => __('Tag(s) added to contact successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function removeTagFromContact()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email'   => ['required', 'email'],
            'tag_ids' => ['required'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = sanitize_email($fields['email']);
        $contact = MailerPressHelper::getContactData($email);

        if (!$contact) {
            return [
                'status_code' => 404,
                'response'    => __('Contact not found.', 'bit-pi')
            ];
        }

        $contactId = isset($contact['contact_id']) ? $contact['contact_id'] : (isset($contact['id']) ? $contact['id'] : '');
        $tagIds = MailerPressHelper::convertStringToArray($fields['tag_ids']);

        global $wpdb;
        $tagsTable = $wpdb->prefix . 'mailerpress_contact_tags';

        foreach ($tagIds as $tagId) {
            if ($tagId > 0) {
                $wpdb->delete(
                    $tagsTable,
                    [
                        'contact_id' => $contactId,
                        'tag_id'     => $tagId,
                    ]
                );
                do_action('mailerpress_contact_tag_removed', $contactId, $tagId);
            }
        }

        return [
            'response'    => __('Tag(s) removed from contact successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function addContactToList()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email'    => ['required', 'email'],
            'list_ids' => ['required'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = isset($fields['email']) ? sanitize_email($fields['email']) : '';
        $contact = MailerPressHelper::getContactData($email);

        if (!$contact) {
            return [
                'status_code' => 404,
                'response'    => __('Contact not found.', 'bit-pi')
            ];
        }

        $contactId = isset($contact['contact_id']) ? $contact['contact_id'] : (isset($contact['id']) ? $contact['id'] : '');
        $listIds = MailerPressHelper::convertStringToArray($fields['list_ids']);

        global $wpdb;
        $listsTable = $wpdb->prefix . 'mailerpress_contact_lists';

        foreach ($listIds as $listId) {
            if ($listId > 0) {
                $wpdb->replace(
                    $listsTable,
                    [
                        'contact_id' => $contactId,
                        'list_id'    => $listId,
                    ]
                );
                do_action('mailerpress_contact_list_added', $contactId, $listId);
            }
        }

        return [
            'response'    => __('Contact added to list(s) successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function removeContactFromList()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'email'    => ['required', 'email'],
            'list_ids' => ['required'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $email = sanitize_email($fields['email']);
        $contact = MailerPressHelper::getContactData($email);

        if (!$contact) {
            return [
                'status_code' => 404,
                'response'    => __('Contact not found.', 'bit-pi')
            ];
        }

        $contactId = isset($contact['contact_id']) ? $contact['contact_id'] : (isset($contact['id']) ? $contact['id'] : '');
        $listIds = MailerPressHelper::convertStringToArray($fields['list_ids']);

        global $wpdb;
        $listsTable = $wpdb->prefix . 'mailerpress_contact_lists';

        foreach ($listIds as $listId) {
            if ($listId > 0) {
                $wpdb->delete(
                    $listsTable,
                    [
                        'contact_id' => $contactId,
                        'list_id'    => $listId,
                    ]
                );
                do_action('mailerpress_contact_list_removed', $contactId, $listId);
            }
        }

        return [
            'response'    => __('Contact removed from list(s) successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function getAllLists()
    {
        if (\function_exists('mailerpress_get_lists')) {
            $lists = mailerpress_get_lists();

            if (!empty($lists)) {
                return [
                    'response'    => $lists,
                    'payload'     => [],
                    'status_code' => 200,
                ];
            }
        }

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_lists';

        $tableExists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $tableName));

        if ($tableExists) {
            $lists = $wpdb->get_results("SELECT * FROM {$tableName}", ARRAY_A);

            return [
                'response'    => $lists,
                'payload'     => [],
                'status_code' => 200,
            ];
        }

        return [
            'status_code' => 500,
            'response'    => __('Failed to retrieve lists.', 'bit-pi')
        ];
    }

    public function getAllTags()
    {
        if (\function_exists('mailerpress_get_tags')) {
            $tags = mailerpress_get_tags();

            if (!empty($tags)) {
                return [
                    'response'    => $tags,
                    'payload'     => [],
                    'status_code' => 200,
                ];
            }
        }

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_tags';

        $tableExists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $tableName));

        if ($tableExists) {
            $tags = $wpdb->get_results("SELECT * FROM {$tableName}", ARRAY_A);

            return [
                'response'    => $tags,
                'payload'     => [],
                'status_code' => 200,
            ];
        }

        return [
            'status_code' => 500,
            'response'    => __('Failed to retrieve tags.', 'bit-pi')
        ];
    }

    public function createList()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'name' => ['required', 'string'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $name = sanitize_text_field($fields['name']);
        $description = isset($fields['description']) ? sanitize_textarea_field($fields['description']) : '';

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_lists';

        $listData = [
            'name'        => $name,
            'description' => $description,
            'sync'        => 0,
            'created_at'  => current_time('mysql'),
            'updated_at'  => current_time('mysql'),
        ];

        $wpdb->insert($tableName, $listData);
        $listId = $wpdb->insert_id;

        if (empty($listId)) {
            return [
                'response'    => __('Failed to create list.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 500,
            ];
        }

        do_action('mailerpress_list_created', $listId);

        return [
            'response'    => __('List created successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function createTag()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'name' => ['required', 'string'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $name = sanitize_text_field($fields['name']);

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_tags';

        $existing = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT tag_id FROM {$tableName} WHERE name = %s",
                $name
            )
        );

        if ($existing) {
            return [
                'response'    => __('Tag already exists.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 409,
            ];
        }

        $tagData = [
            'name' => $name,
            'sync' => 0,
        ];

        $wpdb->insert($tableName, $tagData);
        $tagId = $wpdb->insert_id;

        if (empty($tagId)) {
            return [
                'response'    => __('Failed to create tag.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 500,
            ];
        }

        do_action('mailerpress_tag_created', $tagId);

        return [
            'response'    => __('Tag created successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function deleteList()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'list_id' => ['required', 'integer'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $listId = \intval($fields['list_id']);

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_lists';
        $deleted = $wpdb->delete(
            $tableName,
            ['list_id' => $listId]
        );

        if (!$deleted) {
            return [
                'response'    => __('List not found or could not be deleted.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 404,
            ];
        }

        $wpdb->delete(
            $wpdb->prefix . 'mailerpress_contact_lists',
            ['list_id' => $listId]
        );

        return [
            'response'    => __('List deleted successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function deleteTag()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'tag_id' => ['required', 'integer'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $tagId = \intval($fields['tag_id']);

        global $wpdb;
        $tableName = $wpdb->prefix . 'mailerpress_tags';
        $deleted = $wpdb->delete(
            $tableName,
            ['tag_id' => $tagId]
        );

        if (!$deleted) {
            return [
                'response'    => __('Tag not found or could not be deleted.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 404,
            ];
        }

        $wpdb->delete(
            $wpdb->prefix . 'mailerpress_contact_tags',
            ['tag_id' => $tagId]
        );

        return [
            'response'    => __('Tag deleted successfully.', 'bit-pi'),
            'payload'     => $fields,
            'status_code' => 200,
        ];
    }

    public function getContactsByTag()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'tag_id' => ['required', 'integer'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $tagId = \intval($fields['tag_id']);

        global $wpdb;
        $contactTable = $wpdb->prefix . 'mailerpress_contact';
        $contactTagsTable = $wpdb->prefix . 'mailerpress_contact_tags';

        $contacts = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT c.* FROM {$contactTable} c 
                INNER JOIN {$contactTagsTable} ct ON c.contact_id = ct.contact_id 
                WHERE ct.tag_id = %d",
                $tagId
            ),
            ARRAY_A
        );

        return [
            'status_code' => 200,
            'payload'     => $fields,
            'response'    => [
                'tag_id'   => $tagId,
                'contacts' => $contacts ?? [],
                'count'    => $contacts ? \count($contacts) : 0,
            ]
        ];
    }

    public function getContactsByList()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'list_id' => ['required', 'integer'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $listId = \intval($fields['list_id']);

        global $wpdb;
        $contactTable = $wpdb->prefix . 'mailerpress_contact';
        $contactListsTable = $wpdb->prefix . 'mailerpress_contact_lists';

        $contacts = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT c.* FROM {$contactTable} c 
                INNER JOIN {$contactListsTable} cl ON c.contact_id = cl.contact_id 
                WHERE cl.list_id = %d",
                $listId
            ),
            ARRAY_A
        );

        return [
            'status_code' => 200,
            'payload'     => $fields,
            'response'    => [
                'list_id'  => $listId,
                'contacts' => $contacts ?? [],
                'count'    => $contacts ? \count($contacts) : 0,
            ]
        ];
    }

    public function getAllSegments()
    {
        global $wpdb;
        $segmentsTable = $wpdb->prefix . 'mailerpress_segments';

        $tableExists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $segmentsTable));

        if (!$tableExists) {
            return [
                'response'    => __('Segments feature not available. Install MailerPress Pro for segment support.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404,
            ];
        }

        $segments = $wpdb->get_results(
            "SELECT id, name, created_at, updated_at FROM {$segmentsTable} ORDER BY name ASC",
            ARRAY_A
        );

        return [
            'status_code' => 200,
            'payload'     => [],
            'response'    => [
                'segments' => $segments ?? [],
                'count'    => $segments ? \count($segments) : 0,
            ]
        ];
    }

    public function getContactsBySegment()
    {
        $fields = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'segment_id' => ['required', 'integer'],
        ];

        $errors = MailerPressHelper::validateFieldMap($fields, $rules);

        if ($errors) {
            return $errors;
        }

        $segmentId = \intval($fields['segment_id']);

        global $wpdb;
        $segmentsTable = $wpdb->prefix . 'mailerpress_segments';

        $tableExists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $segmentsTable));

        if (!$tableExists) {
            return [
                'response'    => __('Segments feature not available. Install MailerPress Pro for segment support.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 500,
            ];
        }

        $segment = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$segmentsTable} WHERE id = %d",
                $segmentId
            ),
            ARRAY_A
        );

        if (!$segment) {
            return [
                'response'    => __('Segment not found.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 404,
            ];
        }

        $segmentName = isset($segment['name']) ? $segment['name'] : '';

        $request = new WP_REST_Request('GET', '/mailerpress/v1/getContactSegment');
        $request->set_param('segmentName', $segmentName);
        $request->set_param('_internal_key', wp_hash('mailerpress-internal'));

        $response = rest_do_request($request);

        if ($response->is_error()) {
            return [
                'response'    => __('Could not fetch contacts for this segment.', 'bit-pi'),
                'payload'     => $fields,
                'status_code' => 500,
            ];
        }

        $contacts = $response->get_data();

        return [
            'status_code' => 200,
            'payload'     => $fields,
            'response'    => [
                'segment_id'   => $segmentId,
                'segment_name' => $segmentName,
                'contacts'     => $contacts ?? [],
                'count'        => $contacts ? \count($contacts) : 0,
            ]
        ];
    }
}
