<?php

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

class AIEO_Newsletter_Adapter_TNP extends AIEO_Newsletter_Adapter_Base {

    public function get_id(): string    { return 'tnp'; }
    public function get_label(): string { return 'The Newsletter Plugin (TNP)'; }

    public function get_settings_fields(): array {
        return array(
            array(
                'key'         => 'client_key',
                'label'       => __('Client key', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => true,
                'description' => __('Generated in Newsletter → API → Keys. 40-char hex.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'client_secret',
                'label'       => __('Client secret', 'ai-eshop-optimizer'),
                'type'        => 'password',
                'required'    => true,
                'description' => __('Same screen as the Client key.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'auto_create_lists',
                'label'       => __('Auto-create per-cohort TNP lists', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Set to 1 (default) to have AIEO create + populate TNP lists named "AIEO: All", "AIEO: Lost", "AIEO: Drifting" etc. on first sync. Set to 0 to use only the manual list IDs below.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'list_status',
                'label'       => __('Visibility of auto-created lists', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Either "private" (default — only used internally for AutomateWoo / your campaigns) or "public" (subscribers can see + opt out).', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'list_name_prefix',
                'label'       => __('List name prefix', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Prefix for auto-created list names. Default "AIEO: ". Helps you spot AIEO-managed lists in the TNP admin.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'list_ids',
                'label'       => __('Manual list IDs (optional)', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Comma-separated TNP list IDs. Subscribers will be added to these lists IN ADDITION to the auto-created cohort list. Leave empty to skip.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'cohort_extra_field_id',
                'label'       => __('Cohort extra-field ID (optional)', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('TNP Profile-field ID to receive the cohort slug. Lets you build TNP segments by cohort even when sharing one master list.', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'ltv_extra_field_id',
                'label'       => __('LTV extra-field ID (optional)', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Extra-field ID to receive the customer\'s lifetime value (numeric).', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'score_extra_field_id',
                'label'       => __('Reactivation-score extra-field ID (optional)', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('Extra-field ID for the AIEO reactivation score (0–100).', 'ai-eshop-optimizer'),
            ),
            array(
                'key'         => 'status',
                'label'       => __('New-subscriber status', 'ai-eshop-optimizer'),
                'type'        => 'text',
                'required'    => false,
                'description' => __('One of: confirmed | not_confirmed. Default: confirmed (these customers already opted in via WC purchase).', 'ai-eshop-optimizer'),
            ),
        );
    }

    public function test_connection(): array {
        $url     = $this->base() . '/wp-json/newsletter/v2/lists';
        $headers = $this->auth_headers();

        $resolve = $this->begin_loopback_pin($url);
        $resp = wp_remote_get($url, array(
            'timeout'   => 30,
            'headers'   => $headers,
            'sslverify' => false, 
        ));
        $this->end_loopback_pin($resolve);
        if (is_wp_error($resp)) {
            $msg = $resp->get_error_message();
            
            if (stripos($msg, 'timed out') !== false || stripos($msg, 'cURL error 28') !== false) {
                $msg .= ' — likely a single-worker PHP-FPM loopback deadlock; the live site\'s test will succeed.';
            }
            return array('ok' => false, 'error' => $msg, 'details' => array());
        }
        $code = (int) wp_remote_retrieve_response_code($resp);
        if ($code === 401 || $code === 403) {
            return array('ok' => false, 'error' => 'HTTP ' . $code . ' — bad credentials.', 'details' => array());
        }
        if ($code === 200) {
            $body = json_decode((string) wp_remote_retrieve_body($resp), true);
            $list_count = is_array($body) ? count($body) : 0;
            return array('ok' => true, 'error' => '', 'details' => array(
                'lists_visible' => $list_count,
            ));
        }
        return array(
            'ok'      => false,
            'error'   => 'HTTP ' . $code . ' — ' . wp_remote_retrieve_response_message($resp),
            'details' => array(),
        );
    }

    
    private function begin_loopback_pin(string $url) {
        $home = wp_parse_url((string) home_url('/'));
        $tgt  = wp_parse_url($url);
        if (!is_array($home) || !is_array($tgt)) { return null; }
        if (empty($home['host']) || empty($tgt['host'])) { return null; }
        if (strcasecmp($home['host'], $tgt['host']) !== 0) { return null; }

        $host = $tgt['host'];
        $port = isset($tgt['port']) ? (int) $tgt['port']
              : ((($tgt['scheme'] ?? 'http') === 'https') ? 443 : 80);

        $cb = function ($handle) use ($host, $port) {
            
            curl_setopt($handle, CURLOPT_RESOLVE, array(
                $host . ':' . $port . ':127.0.0.1',
            ));
            return $handle;
        };
        add_filter('http_api_curl', $cb, 10, 1);
        return $cb;
    }

    private function end_loopback_pin($cb): void {
        if ($cb) { remove_filter('http_api_curl', $cb, 10); }
    }

    public function sync_contacts(array $contacts, string $cohort): array {
        $endpoint = $this->base() . '/wp-json/newsletter/v2/subscribers';

        
        
        
        
        $list_assignments = $this->resolve_list_ids($cohort);
        $status = $this->normalize_status();

        $cohort_field_id = (int) ($this->settings['cohort_extra_field_id'] ?? 0);
        $ltv_field_id    = (int) ($this->settings['ltv_extra_field_id']    ?? 0);
        $score_field_id  = (int) ($this->settings['score_extra_field_id']  ?? 0);

        $synced = 0;
        $failed = 0;
        $first_error = '';

        $resolve = $this->begin_loopback_pin($endpoint);
        foreach ($contacts as $c) {
            $email = (string) ($c['email'] ?? '');
            if ($email === '' || !is_email($email)) { $failed++; continue; }

            $extra_fields = array();
            if ($cohort_field_id > 0) {
                $extra_fields[] = array('id' => $cohort_field_id, 'value' => (string) ($c['dormancy_cohort'] ?? $cohort));
            }
            if ($ltv_field_id > 0) {
                $extra_fields[] = array('id' => $ltv_field_id, 'value' => (string) round((float) ($c['ltv'] ?? 0), 2));
            }
            if ($score_field_id > 0) {
                $extra_fields[] = array('id' => $score_field_id, 'value' => (string) (int) ($c['reactivation_score'] ?? 0));
            }

            $body = array(
                'email'  => $email,
                'status' => $status,
            );
            
            
            
            $first_name = trim((string) ($c['first_name'] ?? ''));
            $last_name  = trim((string) ($c['last_name']  ?? ''));
            if ($first_name !== '') { $body['first_name'] = $first_name; }
            if ($last_name  !== '') { $body['last_name']  = $last_name; }
            if (!empty($list_assignments)) {
                $body['lists'] = $list_assignments;
            }
            if (!empty($extra_fields)) {
                $body['extra_fields'] = $extra_fields;
            }

            $resp = wp_remote_post($endpoint, array(
                'timeout' => 15,
                'headers' => array_merge($this->auth_headers(), array(
                    'Content-Type' => 'application/json',
                    'Accept'       => 'application/json',
                )),
                'body'    => wp_json_encode($body),
            ));
            if (is_wp_error($resp)) {
                $failed++;
                if ($first_error === '') { $first_error = $resp->get_error_message(); }
                continue;
            }
            $code = (int) wp_remote_retrieve_response_code($resp);
            if ($code < 200 || $code >= 300) {
                $failed++;
                if ($first_error === '') {
                    $rb = json_decode((string) wp_remote_retrieve_body($resp), true);
                    $msg = is_array($rb) && isset($rb['message']) ? (string) $rb['message'] : '';
                    $first_error = 'HTTP ' . $code . ($msg !== '' ? ' — ' . $msg : '');
                }
                continue;
            }
            $synced++;
        }
        $this->end_loopback_pin($resolve);

        return array(
            'ok'                  => $synced > 0,
            'synced'              => $synced,
            'failed'              => $failed,
            'error'               => $first_error,
            'provider_segment_id' => trim((string) ($this->settings['list_ids'] ?? '')),
        );
    }

    
    public function subscribe_one(string $email, array $opts = array()): array {
        $email = trim($email);
        if ($email === '' || !is_email($email)) {
            return array('ok' => false, 'status' => '', 'list_id' => 0, 'error' => 'invalid_email');
        }
        $status = strtolower((string) ($opts['status'] ?? 'not_confirmed'));
        if (!in_array($status, array('confirmed', 'not_confirmed', 'unsubscribed', 'bounced'), true)) {
            $status = 'not_confirmed';
        }
        
        
        
        
        
        
        $list_assignments = array();
        $primary_list_id  = 0;
        if (!empty($opts['list_id'])) {
            $primary_list_id    = (int) $opts['list_id'];
            $list_assignments[] = array('id' => $primary_list_id, 'value' => 1);
        } elseif (!empty($opts['list_name'])) {
            $primary_list_id = $this->ensure_list((string) $opts['list_name']);
            if ($primary_list_id > 0) { $list_assignments[] = array('id' => $primary_list_id, 'value' => 1); }
        } elseif (!empty($opts['cohort'])) {
            $cohort           = (string) $opts['cohort'];
            $list_assignments = $this->resolve_list_ids($cohort); 
            $primary_list_id  = $this->ensure_list($this->prefix() . $this->cohort_label($cohort));
        }

        $body = array('email' => $email, 'status' => $status);
        $fn = trim((string) ($opts['first_name'] ?? ''));
        $ln = trim((string) ($opts['last_name'] ?? ''));
        if ($fn !== '') { $body['first_name'] = $fn; }
        if ($ln !== '') { $body['last_name']  = $ln; }
        if (!empty($list_assignments)) { $body['lists'] = $list_assignments; }

        $endpoint = $this->base() . '/wp-json/newsletter/v2/subscribers';
        $resolve  = $this->begin_loopback_pin($endpoint);
        $resp = wp_remote_post($endpoint, array(
            'timeout'   => 15,
            'headers'   => array_merge($this->auth_headers(), array(
                'Content-Type' => 'application/json',
                'Accept'       => 'application/json',
            )),
            'body'      => wp_json_encode($body),
            'sslverify' => false,
        ));
        $this->end_loopback_pin($resolve);

        if (is_wp_error($resp)) {
            return array('ok' => false, 'status' => $status, 'list_id' => $primary_list_id, 'error' => $resp->get_error_message());
        }
        $code = (int) wp_remote_retrieve_response_code($resp);
        if ($code < 200 || $code >= 300) {
            $rb  = json_decode((string) wp_remote_retrieve_body($resp), true);
            $msg = is_array($rb) && isset($rb['message']) ? (string) $rb['message'] : '';
            return array('ok' => false, 'status' => $status, 'list_id' => $primary_list_id, 'error' => 'HTTP ' . $code . ($msg !== '' ? ' — ' . $msg : ''));
        }
        return array('ok' => true, 'status' => $status, 'list_id' => $primary_list_id, 'error' => '');
    }

    private function base(): string {
        $custom = trim((string) ($this->settings['site_url'] ?? ''));
        if ($custom !== '') { return rtrim($custom, '/'); }
        return rtrim((string) home_url(''), '/');
    }

    private function auth_headers(): array {
        $key    = (string) ($this->settings['client_key']    ?? '');
        $secret = (string) ($this->settings['client_secret'] ?? '');
        if ($key === '' || $secret === '') { return array(); }
        return array(
            'Authorization' => 'Basic ' . base64_encode($key . ':' . $secret),
        );
    }

    
    private function resolve_list_ids(string $cohort): array {
        $out  = array();
        $seen = array();

        
        $raw = (string) ($this->settings['list_ids'] ?? '');
        if ($raw !== '') {
            foreach (explode(',', $raw) as $id_raw) {
                $id = (int) trim($id_raw);
                if ($id > 0 && !isset($seen[$id])) {
                    $out[] = array('id' => $id, 'value' => 1);
                    $seen[$id] = true;
                }
            }
        }

        
        $auto = (string) ($this->settings['auto_create_lists'] ?? '1');
        if ($auto !== '0' && $auto !== '') {
            $master_id = $this->ensure_list($this->prefix() . 'All');
            $cohort_label = $this->cohort_label($cohort);
            $cohort_id    = $this->ensure_list($this->prefix() . $cohort_label);
            foreach (array($master_id, $cohort_id) as $id) {
                if ($id > 0 && !isset($seen[$id])) {
                    $out[] = array('id' => $id, 'value' => 1);
                    $seen[$id] = true;
                }
            }
        }
        return $out;
    }

    
    private function ensure_list(string $name): int {
        $name = trim($name);
        if ($name === '') { return 0; }

        $opt_key = 'newsletter_lists';
        $opts    = get_option($opt_key, array());
        if (!is_array($opts)) { $opts = array(); }
        $max     = defined('NEWSLETTER_LIST_MAX') ? (int) NEWSLETTER_LIST_MAX : 40;

        
        for ($i = 1; $i <= $max; $i++) {
            $key = 'list_' . $i;
            if (!empty($opts[$key]) && (string) $opts[$key] === $name) {
                return $i;
            }
        }

        
        $status = strtolower((string) ($this->settings['list_status'] ?? 'private')) === 'public' ? 1 : 0;
        for ($i = 1; $i <= $max; $i++) {
            $key = 'list_' . $i;
            if (empty($opts[$key])) {
                $opts[$key]                 = $name;
                $opts[$key . '_status']     = $status;
                $opts[$key . '_forced']     = 0;
                $opts[$key . '_languages']  = array();
                update_option($opt_key, $opts, false);
                return $i;
            }
        }
        return 0; 
    }

    private function prefix(): string {
        $p = (string) ($this->settings['list_name_prefix'] ?? 'AIEO: ');
        return $p;
    }

    private function cohort_label(string $cohort): string {
        $map = array(
            'drifting'     => 'Drifting',
            'lapsed'       => 'Lapsed',
            'long_dormant' => 'Long-dormant',
            'lost'         => 'Lost',
            'active'       => 'Active',
            'newsletter'   => 'Newsletter',   
            'competitions' => 'Competitions', 
        );
        if (isset($map[$cohort])) { return $map[$cohort]; }
        
        return ucwords(str_replace('_', ' ', $cohort));
    }

    private function normalize_status(): string {
        $s = strtolower((string) ($this->settings['status'] ?? 'confirmed'));
        $allowed = array('confirmed', 'not_confirmed', 'unsubscribed', 'bounced');
        return in_array($s, $allowed, true) ? $s : 'confirmed';
    }
}
