<?php
// Exit if accessed directly.
if (!defined('ABSPATH')) {
    exit;
}

require_once INTEGRAZO_WZ_PLUGIN_DIR . 'src/products/zoho_desk/util.php';

if (!class_exists('INTEGRAZO_WZ_Zoho_Desk')) {

    class INTEGRAZO_WZ_Zoho_Desk
    {
        public $refresh_token;
        public $access_token;
        /**
         * 'zoho.com','zoho.in','zoho.eu','zoho.uk','zoho.jp','zoho.sa','zoho.com.cn','zoho.com.au','zohocloud.ca'
         */
        public $data_center;
        public $account_id;
        public $org_id;

        public function __construct($account_details = [])
        {
            $this->refresh_token = $account_details['account_data']['refresh_token'] ?? null;
            $this->org_id        = $account_details['account_data']['org_id'] ?? null;
            $this->data_center   = $account_details['data_center'] ?? 'zoho.com';
            $this->account_id    = $account_details['id'] ?? null;
            $this->access_token  = INTEGRAZO_WZ_Util::getAccessToken($this->account_id);

            // Auto-resolve and persist org_id if missing
            if (empty($this->org_id)) {
                $resolved = $this->get_desk_org_id();
                if ($resolved !== -1) {
                    $this->org_id = $resolved;
                    $account_details['account_data']['org_id'] = $this->org_id;
                    if (class_exists('INTEGRAZO_WZ_Account_Model')) {
                        $account_instance = new INTEGRAZO_WZ_Account_Model();
                        $account_instance->update_account_by_id(
                            $this->account_id,
                            $account_details['account_name'] ?? '',
                            $account_details['account_data'] ?? [],
                            $account_details['input_data'] ?? [],
                            $this->data_center
                        );
                    }
                }
            }
        }

        private function resolve_endpoints(): array
        {
            $dc = strtolower(trim((string)$this->data_center));
            switch ($dc) {
                case 'zoho.in':
                    return ['accounts_base' => 'https://accounts.zoho.in',     'desk_base' => 'https://desk.zoho.in'];
                case 'zoho.eu':
                    return ['accounts_base' => 'https://accounts.zoho.eu',     'desk_base' => 'https://desk.zoho.eu'];
                case 'zoho.uk':
                    return ['accounts_base' => 'https://accounts.zoho.uk',     'desk_base' => 'https://desk.zoho.uk'];
                case 'zoho.jp':
                    return ['accounts_base' => 'https://accounts.zoho.jp',     'desk_base' => 'https://desk.zoho.jp'];
                case 'zoho.sa':
                    return ['accounts_base' => 'https://accounts.zoho.sa',     'desk_base' => 'https://desk.zoho.sa'];
                case 'zoho.com.au':
                    return ['accounts_base' => 'https://accounts.zoho.com.au', 'desk_base' => 'https://desk.zoho.com.au'];
                case 'zoho.com.cn':
                    return ['accounts_base' => 'https://accounts.zoho.com.cn', 'desk_base' => 'https://desk.zoho.com.cn'];
                case 'zohocloud.ca':
                    return ['accounts_base' => 'https://accounts.zohocloud.ca', 'desk_base' => 'https://desk.zoho.ca'];
                case 'zoho.com':
                default:
                    return ['accounts_base' => 'https://accounts.zoho.com',    'desk_base' => 'https://desk.zoho.com'];
            }
        }

        private function build_accounts_url(string $path): string
        {
            $endpoints = $this->resolve_endpoints();
            return rtrim($endpoints['accounts_base'], '/') . '/' . ltrim($path, '/');
        }

        public function build_api_url(string $path): string
        {
            $endpoints = $this->resolve_endpoints();
            $base = rtrim($endpoints['desk_base'], '/');
            $path = ltrim($path, '/');
            return "{$base}/api/v1/{$path}";
        }

        public function record_action_options(): array
        {
            return array();
        }

        public function get_access_token(): bool
        {
            $url = $this->build_accounts_url('/oauth/v2/token');
            $body = [
                'refresh_token' => $this->refresh_token,
                'client_id'     => '1000.R6NADONBVTIS0VZSZ0DE5MNO3DEV7T',
                'client_secret' => '52f6c37069fd0db03ed6025766e968214d35bffbe5',
                'grant_type'    => 'refresh_token',
            ];

            $response = wp_remote_post($url, [
                'body'    => $body,
                'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
                'timeout' => 60,
            ]);

            if (is_wp_error($response)) {
                return false;
            }

            $data = json_decode(wp_remote_retrieve_body($response), true);
            if (!empty($data['access_token'])) {
                INTEGRAZO_WZ_Util::updateAccessToken($this->account_id, $data['access_token']);
                $this->access_token = $data['access_token'];
                return true;
            }
            return false;
        }

        public function is_authentication_error($code): bool
        {
            $auth_errors = [
                'AUTHENTICATION_FAILURE',
                'INVALID_TOKEN',
                'INVALID_OAUTH',
                'UNAUTHORIZED',
                'TOKEN_EXPIRED',
                'INVALID_OAUTH_TOKEN',
                'OAUTH_SCOPE_MISMATCH',
            ];
            return in_array((string)$code, $auth_errors, true);
        }

        /**
         * Return orgId or -1
         */
        public function get_desk_org_id(bool $retry = true)
        {
            try {
                $orgs_url = $this->build_api_url('organizations');
                $orgs_response = wp_remote_get($orgs_url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'Content-Type'  => 'application/json',
                    ],
                    'timeout' => 60,
                ]);
                if (is_wp_error($orgs_response)) return -1;

                $orgs_status = wp_remote_retrieve_response_code($orgs_response);
                $orgs_body   = json_decode(wp_remote_retrieve_body($orgs_response), true);

                if ($orgs_status === 401 && is_array($orgs_body) && isset($orgs_body['errorCode']) && $this->is_authentication_error($orgs_body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->get_desk_org_id(false);
                    }
                    return -1;
                }
                if ($orgs_status < 200 || $orgs_status >= 300) return -1;

                $org_list = [];
                if (isset($orgs_body['data']) && is_array($orgs_body['data'])) $org_list = $orgs_body['data'];
                elseif (is_array($orgs_body))                                  $org_list = $orgs_body;
                if (empty($org_list)) return -1;

                foreach ($org_list as $org) {
                    $org_id = isset($org['id']) ? (string)$org['id'] : (isset($org['orgId']) ? (string)$org['orgId'] : '');
                    if ($org_id === '') continue;

                    $dept_url = $this->build_api_url('departments');
                    $dept_response = wp_remote_get($dept_url, [
                        'headers' => [
                            'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                            'Content-Type'  => 'application/json',
                            'orgId'         => $org_id,
                        ],
                        'timeout' => 60,
                    ]);
                    if (is_wp_error($dept_response)) continue;

                    $dept_status = wp_remote_retrieve_response_code($dept_response);
                    $dept_body   = json_decode(wp_remote_retrieve_body($dept_response), true);
                    if ($dept_status >= 200 && $dept_status < 300) {
                        $dept_list = [];
                        if (isset($dept_body['data']) && is_array($dept_body['data'])) $dept_list = $dept_body['data'];
                        elseif (is_array($dept_body))                                   $dept_list = $dept_body;
                        if (!empty($dept_list)) return $org_id;
                    }
                }
                return -1;
            } catch (Throwable $e) {
                return -1;
            }
        }

        /**
         * Return departments list on success, or ['error' => '...'] on failure
         */
        public function get_desk_departments($retry = true)
        {

            try {
                if (empty($this->org_id)) {
                    return ['error' => 'Organization ID is not set.'];
                }

                $url = $this->build_api_url('departments');
                $response = wp_remote_get($url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'Content-Type'  => 'application/json',
                        'orgId'         => $this->org_id,
                    ],
                    'timeout' => 60,
                ]);

                if (is_wp_error($response)) {
                    return ['error' => 'Failed to connect to Zoho Desk.'];
                }

                $status_code = wp_remote_retrieve_response_code($response);
                $body        = json_decode(wp_remote_retrieve_body($response), true);

                if ($status_code === 401 && isset($body['errorCode']) && $this->is_authentication_error($body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->get_desk_departments(false);
                    }
                    return ['error' => 'Authentication failed: token invalid or expired.'];
                }

                if ($status_code === 429) return ['error' => 'Rate limit reached. Try again later.'];
                if ($status_code >= 500)  return ['error' => 'Zoho Desk server error. Try again later.'];

                $data = isset($body['data']) ? $body['data'] : (is_array($body) ? $body : []);
                if (empty($data)) {
                    return ['error' => 'No departments found in your Zoho Desk account.'];
                }

                return $data; // success: raw list
            } catch (Throwable $e) {
                return ['error' => 'Unexpected error while retrieving departments.'];
            }
        }

        /**
         * Return fields list on success, or ['error' => '...'] on failure
         */
        public function get_desk_departments_fields($department_id, $retry = true)
        {
            try {
                if (empty($this->org_id))  return ['error' => 'Organization ID is not set.'];
                if (empty($department_id)) return ['error' => 'Department ID is required.'];

                $url = $this->build_api_url('organizationFields') . '?departmentId=' . urlencode($department_id) . '&module=tickets';
                $response = wp_remote_get($url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'Content-Type'  => 'application/json',
                        'orgId'         => $this->org_id,
                    ],
                    'timeout' => 60,
                ]);

                if (is_wp_error($response)) {
                    return ['error' => 'Failed to connect to Zoho Desk.'];
                }

                $status_code = wp_remote_retrieve_response_code($response);
                $body        = json_decode(wp_remote_retrieve_body($response), true);

                if ($status_code === 401 && isset($body['errorCode']) && $this->is_authentication_error($body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->get_desk_departments_fields($department_id, false);
                    }
                    return ['error' => 'Authentication failed: token invalid or expired.'];
                }

                if ($status_code === 429) return ['error' => 'Rate limit reached. Try again later.'];
                if ($status_code >= 500)  return ['error' => 'Zoho Desk server error. Try again later.'];

                // Raw fields array from API (either in "data" or the body itself)
                $raw = isset($body['data']) ? $body['data'] : (is_array($body) ? $body : []);
                if (empty($raw)) {
                    return ['error' => 'No ticket fields found for this department.'];
                }

                // Fields that must be treated as mandatory regardless of API "isMandatory"
                $force_mandatory = ['contactId', 'email', 'subject'];

                // Fields we should skip entirely
                $skip_fields = ['departmentId', 'accountId'];

                $normalized = [];
                foreach ($raw as $f) {
                    $api_name  = isset($f['apiName']) ? (string)$f['apiName'] : (isset($f['name']) ? (string)$f['name'] : '');
                    if ($api_name === '') {
                        continue;
                    }

                    // 🚫 Skip departmentId & accountId
                    if (in_array($api_name, $skip_fields, true)) {
                        continue;
                    }

                    // Label
                    $label = isset($f['displayLabel']) ? (string)$f['displayLabel']
                        : (isset($f['i18NLabel']) ? (string)$f['i18NLabel']
                            : (isset($f['name']) ? (string)$f['name'] : $api_name));

                    // Data type
                    $data_type = isset($f['type']) ? (string)$f['type'] : '';

                    // is_custom
                    $is_custom = !empty($f['isCustomField']);

                    // ✅ Prefix api_name if custom
                    if ($is_custom) {
                        $api_name = 'integrazo_wz_cf_' . $api_name;
                    }

                    // system_mandatory
                    $system_mandatory = in_array($api_name, $force_mandatory, true);

                    // pick_list_values
                    $pick_list_values = [];
                    if (!empty($f['allowedValues']) && is_array($f['allowedValues'])) {
                        foreach ($f['allowedValues'] as $opt) {
                            $val = isset($opt['value']) ? (string)$opt['value'] : '';
                            if ($val !== '') {
                                $pick_list_values[] = [
                                    'actual_value'  => $val,
                                    'display_value' => $val,
                                ];
                            }
                        }
                    } elseif (!empty($f['pickListValues']) && is_array($f['pickListValues'])) {
                        foreach ($f['pickListValues'] as $opt) {
                            $val  = isset($opt['actualValue']) ? (string)$opt['actualValue'] : (isset($opt['value']) ? (string)$opt['value'] : '');
                            $disp = isset($opt['displayValue']) ? (string)$opt['displayValue'] : ($val !== '' ? $val : '');
                            if ($val !== '') {
                                $pick_list_values[] = [
                                    'actual_value'  => $val,
                                    'display_value' => $disp,
                                ];
                            }
                        }
                    }

                    $normalized[] = [
                        'api_name'         => $api_name,
                        'field_label'      => $label,
                        'data_type'        => $data_type,
                        'system_mandatory' => $system_mandatory,
                        'is_custom'        => $is_custom,
                        'pick_list_values' => $pick_list_values,
                    ];
                }

                if (empty($normalized)) {
                    return ['error' => 'No usable ticket fields found for this department.'];
                }

                return $normalized;
            } catch (Throwable $e) {
                return ['error' => 'Unexpected error while retrieving ticket fields.'];
            }
        }




        /**
         * Create ticket (ensuring contact exists). Returns created ticket body or INTEGRAZO_WZ_Product_Util::create_error_response(...)
         */
        public function add_desk_ticket_with_contact($department_id, $ticket_data, $retry = true)
        {
            try {
                if (empty($this->org_id))    return INTEGRAZO_WZ_Product_Util::create_error_response('ORG_ID_MISSING', 'Organization ID is not set.');
                if (empty($department_id))   return INTEGRAZO_WZ_Product_Util::create_error_response('DEPARTMENT_ID_MISSING', 'Department ID is required.');

                $contact_email = $ticket_data['email'] ?? '';
                if ($contact_email === '')   return INTEGRAZO_WZ_Product_Util::create_error_response('EMAIL_MISSING', 'Email is required to create/find a contact.');

                // Find existing contact
                $contact_id_result = $this->get_zoho_desk_contact_id_by_email($contact_email);
                if (is_array($contact_id_result) && isset($contact_id_result['category'])) {
                    return $contact_id_result;
                }

                $contact_id = $contact_id_result;

                // Create contact if needed
                if (!$contact_id) {
                    $lastName = $ticket_data['contactId'] ?? 'Visitor';
                    $contact_create_result = $this->create_zoho_desk_contact([
                        'lastName' => $lastName,
                        'email'    => $contact_email,
                    ]);
                    if (is_array($contact_create_result) && isset($contact_create_result['category'])) {
                        return $contact_create_result;
                    }
                    $contact_id = $contact_create_result;
                }

                if (!$contact_id) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('CONTACT_CREATION_FAILED', 'Unable to create or find a contact for this email.');
                }

                // Prepare ticket payload
                $ticket_payload                 = $ticket_data;
                $ticket_payload['contactId']    = $contact_id;
                $ticket_payload['departmentId'] = $department_id;

                // ✅ Ensure status is set (default = Open)
                if (empty($ticket_payload['status'])) {
                    $ticket_payload['status'] = 'Open';
                }

                // ✅ Move all "integrazo_wz_cf_" prefixed keys into cf[]
                $custom_fields = [];
                foreach ($ticket_payload as $key => $value) {
                    if (strpos($key, 'integrazo_wz_cf_') === 0) {
                        $cf_key = substr($key, strlen('integrazo_wz_cf_')); // remove prefix
                        $custom_fields[$cf_key] = $value;
                        unset($ticket_payload[$key]); // remove from root
                    }
                }
                if (!empty($custom_fields)) {
                    $ticket_payload['cf'] = $custom_fields;
                }

                $url = $this->build_api_url('tickets');
                $response = wp_remote_post($url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'Content-Type'  => 'application/json',
                        'orgId'         => $this->org_id,
                    ],
                    'body'    => wp_json_encode($ticket_payload),
                    'timeout' => 60,
                ]);
                if (is_wp_error($response)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('NETWORK_ISSUE', 'Failed to connect to Zoho Desk.');
                }

                $status_code = wp_remote_retrieve_response_code($response);
                $body        = json_decode(wp_remote_retrieve_body($response), true);

                if (!is_array($body)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('INVALID_RESPONSE', 'Invalid response from API.');
                }

                if ($status_code === 401 && isset($body['errorCode']) && $this->is_authentication_error($body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->add_desk_ticket_with_contact($department_id, $ticket_data, false);
                    }
                    return INTEGRAZO_WZ_Product_Util::create_error_response('AUTHENTICATION_FAILURE', 'Access token invalid or expired.', $body);
                }

                if (isset($body['errorCode'])) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response($body['errorCode'], 'Zoho Desk API returned an error.', $body);
                }

                return INTEGRAZO_WZ_Product_Util::create_error_response('SUCCESS', "Ticket created successfully.", $body);
            } catch (Throwable $e) {
                return INTEGRAZO_WZ_Product_Util::create_error_response('UNEXPECTED_ERROR', 'Error while creating ticket.', ['exception' => $e->getMessage()]);
            }
        }

        /**
         * Returns contactId, or INTEGRAZO_WZ_Product_Util::create_error_response(...) on error, or null if not found.
         */
        private function get_zoho_desk_contact_id_by_email($email, $retry = true)
        {
            try {
                if (empty($this->org_id)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('ORG_ID_MISSING', 'Organization ID is not set.');
                }

                $url = $this->build_api_url('contacts/search') . '?email=' . urlencode($email);
                $response = wp_remote_get($url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'orgId'         => $this->org_id,
                    ],
                    'timeout' => 30,
                ]);

                if (is_wp_error($response)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('NETWORK_ISSUE', 'Failed to connect to Zoho Desk.');
                }

                $status_code = wp_remote_retrieve_response_code($response);
                $body        = json_decode(wp_remote_retrieve_body($response), true);

                if ($status_code === 401 && isset($body['errorCode']) && $this->is_authentication_error($body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->get_zoho_desk_contact_id_by_email($email, false);
                    }
                    return INTEGRAZO_WZ_Product_Util::create_error_response('AUTHENTICATION_FAILURE', 'Access token invalid or expired.', $body);
                }

                if (!is_array($body)) {
                    return null;
                }

                if (isset($body['data'][0]['id'])) {
                    return $body['data'][0]['id'];
                }

                return null;
            } catch (Throwable $e) {
                return INTEGRAZO_WZ_Product_Util::create_error_response('UNEXPECTED_ERROR', 'Error while searching contact.', ['exception' => $e->getMessage()]);
            }
        }

        /**
         * Returns new contactId, or INTEGRAZO_WZ_Product_Util::create_error_response(...) on error
         */
        private function create_zoho_desk_contact($contact_data, $retry = true)
        {
            try {
                if (empty($this->org_id)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('ORG_ID_MISSING', 'Organization ID is not set.');
                }

                $url = $this->build_api_url('contacts');
                $response = wp_remote_post($url, [
                    'headers' => [
                        'Authorization' => 'Zoho-oauthtoken ' . $this->access_token,
                        'Content-Type'  => 'application/json',
                        'orgId'         => $this->org_id,
                    ],
                    'body'    => wp_json_encode($contact_data),
                    'timeout' => 30,
                ]);

                if (is_wp_error($response)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('NETWORK_ISSUE', 'Failed to connect to Zoho Desk.');
                }

                $status_code = wp_remote_retrieve_response_code($response);
                $body        = json_decode(wp_remote_retrieve_body($response), true);

                if (!is_array($body)) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response('INVALID_RESPONSE', 'Invalid response from API.');
                }

                if ($status_code === 401 && isset($body['errorCode']) && $this->is_authentication_error($body['errorCode'])) {
                    if ($retry && $this->get_access_token()) {
                        return $this->create_zoho_desk_contact($contact_data, false);
                    }
                    return INTEGRAZO_WZ_Product_Util::create_error_response('AUTHENTICATION_FAILURE', 'Access token invalid or expired.', $body);
                }

                if (isset($body['errorCode'])) {
                    return INTEGRAZO_WZ_Product_Util::create_error_response($body['errorCode'], 'Zoho Desk API returned an error.', $body);
                }

                if (isset($body['id'])) {
                    return $body['id'];
                }

                return INTEGRAZO_WZ_Product_Util::create_error_response('INVALID_RESPONSE', 'Contact creation returned unexpected body.', $body);
            } catch (Throwable $e) {
                return INTEGRAZO_WZ_Product_Util::create_error_response('UNEXPECTED_ERROR', 'Error while creating contact.', ['exception' => $e->getMessage()]);
            }
        }
    }
}
