<?php
if (!defined('ABSPATH')) {
    exit;
}

class VMO_Promotion_X_Connector extends VMO_Promotion_OAuth2_Connector {
    public function connect_account(array $input) {
        $settings = $this->get_settings();
        $missing = $this->get_missing_required_fields($settings);
        $user_id = (int) ($input['user_id'] ?? 0);

        if ($user_id <= 0) {
            return new WP_Error('missing_user', 'A valid user is required before starting provider authorization.');
        }

        if (!empty($missing)) {
            return new WP_Error(
                'missing_credentials',
                sprintf('Missing required credentials for %s: %s.', $this->platform_label, implode(', ', array_map(array('VMO_Promotion_Admin_Settings', 'label_for_field'), $missing))),
                array(
                    'platform_key' => $this->platform_key,
                    'missing_fields' => $missing,
                )
            );
        }

        $scopes = $this->get_requested_scopes($settings);
        $pkce = $this->build_pkce_pair();
        $state = $this->create_oauth_state($user_id, array(
            'platform_key' => $this->platform_key,
            'scopes' => $scopes,
            'code_verifier' => $pkce['verifier'],
            'code_challenge' => $pkce['challenge'],
        ));

        if ($this->store) {
            $this->store->log_event(
                $user_id,
                'provider_authorization_started',
                sprintf('OAuth authorization started for %s.', $this->platform_label),
                array(
                    'platform_key' => $this->platform_key,
                    'scopes' => $scopes,
                )
            );
        }

        return array(
            'platform_key' => $this->platform_key,
            'platform_label' => $this->platform_label,
            'connect_supported' => !empty($this->capabilities['connect_supported']),
            'credentials_ready' => true,
            'missing_fields' => array(),
            'callback_url' => $this->get_callback_url(),
            'webhook_url' => $this->get_webhook_url(),
            'requires_redirect' => true,
            'scopes' => $scopes,
            'auth_url' => $this->build_authorization_url($settings, $scopes, $state),
            'message' => sprintf('Redirect the user to %s to complete authorization.', $this->platform_label),
        );
    }

    protected function build_authorization_url(array $settings, array $scopes, $state) {
        $state_payload = get_transient($this->oauth_state_key($state));
        $challenge = sanitize_text_field($state_payload['code_challenge'] ?? '');

        return add_query_arg(array(
            'response_type' => 'code',
            'client_id' => $this->get_client_identifier($settings),
            'redirect_uri' => $this->get_callback_url(),
            'scope' => implode(' ', $scopes),
            'state' => $state,
            'code_challenge' => $challenge,
            'code_challenge_method' => 'S256',
        ), 'https://x.com/i/oauth2/authorize');
    }

    protected function get_token_endpoint() {
        return 'https://api.x.com/2/oauth2/token';
    }

    protected function build_token_request_body($code, array $state_payload, array $settings) {
        $body = array(
            'grant_type' => 'authorization_code',
            'code' => (string) $code,
            'redirect_uri' => $this->get_callback_url(),
            'client_id' => $this->get_client_identifier($settings),
            'code_verifier' => sanitize_text_field($state_payload['code_verifier'] ?? ''),
        );

        $secret = $this->get_client_secret($settings);
        if ($secret !== '') {
            $body['client_secret'] = $secret;
        }

        return $body;
    }

    protected function build_refresh_request_body($refresh_token, array $settings) {
        $body = array(
            'grant_type' => 'refresh_token',
            'refresh_token' => (string) $refresh_token,
            'client_id' => $this->get_client_identifier($settings),
        );

        $secret = $this->get_client_secret($settings);
        if ($secret !== '') {
            $body['client_secret'] = $secret;
        }

        return $body;
    }

    protected function discover_remote_accounts($user_id, array $token_context, array $request_context = array()) {
        $access_token = (string) ($token_context['access_token'] ?? '');
        if ($access_token === '') {
            return array();
        }

        $me = $this->x_get('https://api.x.com/2/users/me', $access_token, array(
            'user.fields' => 'id,name,username,profile_image_url,verified,public_metrics',
        ));
        if (is_wp_error($me)) {
            return $me;
        }

        $data = (array) ($me['data'] ?? array());
        $user_id_remote = sanitize_text_field($data['id'] ?? '');
        if ($user_id_remote === '') {
            return array();
        }

        $username = sanitize_text_field($data['username'] ?? '');
        $display_name = sanitize_text_field($data['name'] ?? ($username !== '' ? '@' . $username : 'X User'));

        return array(
            array(
                'platform_key' => 'x',
                'platform_label' => 'X',
                'external_account_id' => $user_id_remote,
                'display_name' => $display_name,
                'auth_status' => 'connected',
                'connection_metadata' => array(
                    'connection_role' => 'x_user',
                    'user_id' => $user_id_remote,
                    'username' => $username,
                    'profile_image_url' => esc_url_raw($data['profile_image_url'] ?? ''),
                    'verified' => !empty($data['verified']),
                    'public_metrics' => (array) ($data['public_metrics'] ?? array()),
                ),
            ),
        );
    }

    public function publish_text_post(array $input) {
        $account = $this->get_platform_account_record($input);
        if (empty($account['access_token'])) {
            return new WP_Error('missing_connected_account', 'A connected X account is required before publishing.');
        }

        $content_item = (array) ($input['content_item'] ?? array());
        $text = $this->get_post_text($content_item);
        if ($text === '') {
            return new WP_Error('missing_post_text', 'X publishing requires caption or post text.');
        }

        $response = $this->x_post('https://api.x.com/2/tweets', $account['access_token'], array(
            'text' => $text,
        ));
        if (is_wp_error($response)) {
            return $response;
        }

        return array(
            'provider_post_id' => sanitize_text_field($response['data']['id'] ?? ''),
            'message' => 'Published to X.',
            'response' => $response,
        );
    }

    public function publish_media_post(array $input) {
        return new WP_Error(
            'provider_not_ready',
            'X media publishing is not activated yet in this build. The X media upload path requires additional OAuth 1.0a user-context media credentials beyond the current generic connector flow.'
        );
    }

    public function list_replies(array $input) {
        return new WP_Error('provider_not_ready', 'X reply ingestion is not activated yet in this build.');
    }

    public function reply_to_comment(array $input) {
        $account = $this->get_platform_account_record($input);
        if (empty($account['access_token'])) {
            return new WP_Error('missing_connected_account', 'A connected X account is required before replying.');
        }

        $comment_id = sanitize_text_field($input['comment_id'] ?? $input['provider_comment_id'] ?? $input['in_reply_to_id'] ?? '');
        if ($comment_id === '') {
            return new WP_Error('missing_comment_id', 'X reply publishing requires a target post ID.');
        }

        $text = sanitize_textarea_field($input['message'] ?? $input['text'] ?? '');
        if ($text === '' && !empty($input['content_item'])) {
            $text = $this->get_post_text((array) $input['content_item']);
        }

        if ($text === '') {
            return new WP_Error('missing_reply_text', 'X reply publishing requires reply text.');
        }

        $response = $this->x_post('https://api.x.com/2/tweets', $account['access_token'], array(
            'text' => $text,
            'reply' => array(
                'in_reply_to_tweet_id' => $comment_id,
            ),
        ));
        if (is_wp_error($response)) {
            return $response;
        }

        return array(
            'provider_post_id' => sanitize_text_field($response['data']['id'] ?? ''),
            'message' => 'Reply published to X.',
            'response' => $response,
        );
    }

    public function fetch_metrics(array $input) {
        $account = $this->get_platform_account_record($input);
        if (empty($account['access_token'])) {
            return new WP_Error('missing_connected_account', 'A connected X account is required before loading metrics.');
        }

        $post_id = sanitize_text_field($input['provider_post_id'] ?? $input['post_id'] ?? $input['tweet_id'] ?? '');
        if ($post_id === '' && !empty($input['distribution_job']['provider_post_id'])) {
            $post_id = sanitize_text_field($input['distribution_job']['provider_post_id']);
        }

        if ($post_id === '') {
            return new WP_Error('missing_post_id', 'X metrics lookup requires a provider post ID.');
        }

        $response = $this->x_get('https://api.x.com/2/tweets', $account['access_token'], array(
            'ids' => $post_id,
            'tweet.fields' => 'created_at,public_metrics',
        ));
        if (is_wp_error($response)) {
            return $response;
        }

        $tweet = array();
        foreach ((array) ($response['data'] ?? array()) as $candidate) {
            if (sanitize_text_field($candidate['id'] ?? '') === $post_id) {
                $tweet = (array) $candidate;
                break;
            }
        }

        if (empty($tweet)) {
            return new WP_Error('provider_api_error', 'X metrics lookup did not return the requested post.', $response);
        }

        $public_metrics = (array) ($tweet['public_metrics'] ?? array());
        $likes = (int) ($public_metrics['like_count'] ?? 0);
        $replies = (int) ($public_metrics['reply_count'] ?? 0);
        $shares = (int) ($public_metrics['retweet_count'] ?? 0);
        $quotes = (int) ($public_metrics['quote_count'] ?? 0);

        return array(
            'platform_key' => 'x',
            'provider_post_id' => $post_id,
            'snapshot_time' => current_time('mysql'),
            'metrics' => array(
                'likes' => $likes,
                'comments' => $replies,
                'shares' => $shares,
                'quotes' => $quotes,
                'engagements' => $likes + $replies + $shares + $quotes,
            ),
            'response' => $response,
        );
    }

    protected function x_get($url, $access_token, array $query = array()) {
        $response = $this->api_get($url, $access_token, $query);
        return $this->normalize_x_response($response);
    }

    protected function x_post($url, $access_token, array $body = array()) {
        $response = $this->api_post($url, $access_token, $body, array(), true);
        return $this->normalize_x_response($response);
    }

    protected function normalize_x_response($response) {
        if (is_wp_error($response)) {
            return $response;
        }

        if (!empty($response['errors']) && is_array($response['errors'])) {
            $error = (array) $response['errors'][0];
            return new WP_Error(
                sanitize_key($error['type'] ?? 'provider_api_error'),
                sanitize_text_field($error['detail'] ?? $error['message'] ?? 'X API request failed.'),
                array(
                    'platform_key' => 'x',
                    'response' => $response,
                )
            );
        }

        return $response;
    }

    protected function get_post_text(array $content_item) {
        $text = $this->get_post_caption($content_item);
        if ($text === '') {
            $text = sanitize_text_field($content_item['title'] ?? '');
        }

        return $this->truncate_text($text, 280);
    }

    protected function build_pkce_pair() {
        $verifier = $this->base64_url_encode(random_bytes(48));
        $verifier = preg_replace('/[^A-Za-z0-9\-._~]/', '', $verifier);
        if (strlen($verifier) < 43) {
            $verifier .= str_repeat('a', 43 - strlen($verifier));
        }
        if (strlen($verifier) > 128) {
            $verifier = substr($verifier, 0, 128);
        }

        $challenge = $this->base64_url_encode(hash('sha256', $verifier, true));

        return array(
            'verifier' => $verifier,
            'challenge' => $challenge,
        );
    }

    protected function base64_url_encode($value) {
        return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
    }

    protected function truncate_text($value, $limit) {
        $value = trim((string) $value);
        if ($value === '') {
            return '';
        }

        if (function_exists('mb_strlen') && function_exists('mb_substr')) {
            return mb_strlen($value) > $limit ? rtrim(mb_substr($value, 0, $limit - 1)) : $value;
        }

        return strlen($value) > $limit ? rtrim(substr($value, 0, $limit - 1)) : $value;
    }
}
