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

class VMO_Promotion_Mastodon_Connector extends VMO_Promotion_OAuth2_Connector {
    protected function build_authorization_url(array $settings, array $scopes, $state) {
        $base_url = untrailingslashit((string) ($settings['base_url'] ?? ''));
        return add_query_arg(array(
            'client_id' => $this->get_client_identifier($settings),
            'redirect_uri' => $this->get_callback_url(),
            'response_type' => 'code',
            'scope' => implode(' ', $scopes),
            'state' => $state,
        ), $base_url . '/oauth/authorize');
    }

    protected function get_token_endpoint() {
        $settings = $this->get_settings();
        return untrailingslashit((string) ($settings['base_url'] ?? '')) . '/oauth/token';
    }

    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();
        }

        $account = $this->mastodon_get('/api/v1/accounts/verify_credentials', $access_token);
        if (is_wp_error($account)) {
            return $account;
        }

        $account_id = sanitize_text_field($account['id'] ?? '');
        return array(
            array(
                'platform_key' => 'mastodon',
                'platform_label' => 'Mastodon',
                'external_account_id' => $account_id,
                'display_name' => sanitize_text_field($account['display_name'] ?? $account['username'] ?? ('Mastodon Account ' . $account_id)),
                'auth_status' => 'connected',
                'connection_metadata' => array(
                    'connection_role' => 'mastodon_account',
                    'username' => sanitize_text_field($account['username'] ?? ''),
                    'acct' => sanitize_text_field($account['acct'] ?? ''),
                ),
            ),
        );
    }

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

        $content_item = (array) ($input['content_item'] ?? array());
        $response = $this->mastodon_post('/api/v1/statuses', $account['access_token'], array(
            'status' => $this->get_caption($content_item),
            'visibility' => 'public',
        ));

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

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

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

        $content_item = (array) ($input['content_item'] ?? array());
        $asset = $this->extract_asset($content_item);
        if (empty($asset['url'])) {
            return $this->publish_text_post($input);
        }

        $upload = $this->upload_media($account['access_token'], $asset);
        if (is_wp_error($upload)) {
            return $upload;
        }

        $response = $this->mastodon_post('/api/v1/statuses', $account['access_token'], array(
            'status' => $this->get_caption($content_item),
            'visibility' => 'public',
            'media_ids[]' => sanitize_text_field($upload['id'] ?? ''),
        ), false);

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

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

    public function list_replies(array $input) {
        $account = $this->get_account($input);
        $job = (array) ($input['job'] ?? array());
        $status_id = sanitize_text_field($input['provider_post_id'] ?? ($job['provider_post_id'] ?? ''));
        if (empty($account['access_token']) || $status_id === '') {
            return new WP_Error('missing_provider_post', 'A Mastodon status ID is required before loading replies.');
        }

        $response = $this->mastodon_get('/api/v1/statuses/' . rawurlencode($status_id) . '/context', $account['access_token']);
        if (is_wp_error($response)) {
            return $response;
        }

        return array(
            'platform_key' => 'mastodon',
            'replies' => array_values((array) ($response['descendants'] ?? array())),
        );
    }

    public function reply_to_comment(array $input) {
        $account = $this->get_account($input);
        $status_id = sanitize_text_field($input['comment_id'] ?? '');
        $message = sanitize_textarea_field($input['message'] ?? '');
        if (empty($account['access_token']) || $status_id === '' || $message === '') {
            return new WP_Error('missing_reply_context', 'A Mastodon status ID and reply message are required.');
        }

        $response = $this->mastodon_post('/api/v1/statuses', $account['access_token'], array(
            'status' => $message,
            'in_reply_to_id' => $status_id,
            'visibility' => 'public',
        ));

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

        return array(
            'platform_key' => 'mastodon',
            'provider_reply_id' => sanitize_text_field($response['id'] ?? ''),
            'message' => 'Reply sent to Mastodon.',
            'response' => $response,
        );
    }

    public function fetch_metrics(array $input) {
        return new WP_Error('provider_not_ready', 'Mastodon metrics normalization is not finalized yet in this build.');
    }

    protected function mastodon_get($path, $access_token, array $query = array()) {
        $settings = $this->get_settings();
        $base_url = untrailingslashit((string) ($settings['base_url'] ?? ''));
        return $this->api_get($base_url . $path, $access_token, $query);
    }

    protected function mastodon_post($path, $access_token, array $body = array(), $json = false) {
        $settings = $this->get_settings();
        $base_url = untrailingslashit((string) ($settings['base_url'] ?? ''));
        return $this->api_post($base_url . $path, $access_token, $body, array(), $json);
    }

    protected function upload_media($access_token, array $asset) {
        $settings = $this->get_settings();
        $base_url = untrailingslashit((string) ($settings['base_url'] ?? ''));

        $asset_response = wp_remote_get(esc_url_raw($asset['url'] ?? ''), array(
            'timeout' => 120,
        ));
        if (is_wp_error($asset_response)) {
            return $asset_response;
        }

        $binary = wp_remote_retrieve_body($asset_response);
        if ($binary === '') {
            return new WP_Error('empty_asset', 'Mastodon upload could not read the selected media asset.');
        }

        $boundary = '----VMOMastodon' . wp_generate_password(16, false, false);
        $eol = "\r\n";
        $filename = sanitize_file_name($asset['name'] ?? 'asset');
        $mime = sanitize_text_field($asset['type'] ?? 'application/octet-stream');

        $body = '--' . $boundary . $eol;
        $body .= 'Content-Disposition: form-data; name="file"; filename="' . $filename . '"' . $eol;
        $body .= 'Content-Type: ' . $mime . $eol . $eol;
        $body .= $binary . $eol;
        $body .= '--' . $boundary . '--' . $eol;

        $response = wp_remote_post($base_url . '/api/v2/media', array(
            'timeout' => 180,
            'headers' => array(
                'Authorization' => 'Bearer ' . $access_token,
                'Accept' => 'application/json',
                'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
            ),
            'body' => $body,
        ));

        return $this->parse_remote_response($response);
    }

    protected function get_account(array $input) {
        if (!$this->store || !method_exists($this->store, 'get_connected_account_auth_rows')) {
            return (array) ($input['connected_account'] ?? array());
        }

        $user_id = (int) ($input['user_id'] ?? 0);
        if ($user_id <= 0) {
            return (array) ($input['connected_account'] ?? array());
        }

        $target = (array) ($input['connected_account'] ?? array());
        $rows = $this->store->get_connected_account_auth_rows($user_id, 'mastodon');
        if (empty($rows)) {
            return $target;
        }

        if (!empty($target['id'])) {
            foreach ($rows as $row) {
                if ((int) $row['id'] === (int) $target['id']) {
                    return $row;
                }
            }
        }

        return $rows[0];
    }

    protected function get_caption(array $content_item) {
        $caption = sanitize_textarea_field($content_item['caption_master'] ?? '');
        $cta = esc_url_raw($content_item['cta_url'] ?? '');
        if ($cta !== '' && strpos($caption, $cta) === false) {
            $caption = trim($caption . "\n\n" . $cta);
        }

        return trim($caption);
    }

    protected function extract_asset(array $content_item) {
        $bundle = (array) ($content_item['media_bundle'] ?? array());
        $assets = array_values((array) ($bundle['manual_assets'] ?? array()));
        if (empty($assets)) {
            return array();
        }

        return (array) $assets[0];
    }
}
