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

class VMO_Promotion_LinkedIn_Connector extends VMO_Promotion_OAuth2_Connector {
    protected function build_authorization_url(array $settings, array $scopes, $state) {
        return add_query_arg(array(
            'response_type' => 'code',
            'client_id' => $this->get_client_identifier($settings),
            'redirect_uri' => $this->get_callback_url(),
            'state' => $state,
            'scope' => implode(' ', $scopes),
        ), 'https://www.linkedin.com/oauth/v2/authorization');
    }

    protected function get_token_endpoint() {
        return 'https://www.linkedin.com/oauth/v2/accessToken';
    }

    public function refresh_auth(array $input) {
        return $this->connect_account($input);
    }

    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->linkedin_get('https://api.linkedin.com/v2/me', $access_token);
        if (is_wp_error($me)) {
            return $me;
        }

        $person_id = sanitize_text_field($me['id'] ?? '');
        $person_name = trim(sanitize_text_field(($me['localizedFirstName'] ?? '') . ' ' . ($me['localizedLastName'] ?? '')));
        if ($person_name === '') {
            $person_name = 'LinkedIn Member';
        }

        $accounts = array(
            array(
                'platform_key' => 'linkedin',
                'platform_label' => 'LinkedIn',
                'external_account_id' => $person_id,
                'display_name' => $person_name,
                'auth_status' => 'connected',
                'connection_metadata' => array(
                    'connection_role' => 'member',
                    'author_urn' => 'urn:li:person:' . $person_id,
                ),
            ),
        );

        $acls = $this->linkedin_get('https://api.linkedin.com/v2/organizationAcls', $access_token, array(
            'q' => 'roleAssignee',
            'roleAssignee' => 'urn:li:person:' . $person_id,
            'role' => 'ADMINISTRATOR',
            'state' => 'APPROVED',
        ));

        if (!is_wp_error($acls)) {
            $org_urns = array();
            foreach ((array) ($acls['elements'] ?? array()) as $element) {
                $urn = sanitize_text_field($element['organizationTarget'] ?? ($element['organization'] ?? ''));
                if ($urn !== '') {
                    $org_urns[] = $urn;
                }
            }

            $org_urns = array_values(array_unique($org_urns));
            if (!empty($org_urns)) {
                $org_lookup = $this->linkedin_get('https://api.linkedin.com/rest/organizations', $access_token, array(
                    'ids' => 'List(' . implode(',', array_map(function($urn) {
                        return preg_replace('/^urn:li:organization:/', '', $urn);
                    }, $org_urns)) . ')',
                ));

                $org_results = is_array($org_lookup['results'] ?? null) ? $org_lookup['results'] : array();
                foreach ($org_urns as $org_urn) {
                    $org_id = preg_replace('/^urn:li:organization:/', '', $org_urn);
                    $org = is_array($org_results[$org_id] ?? null) ? $org_results[$org_id] : array();
                    $accounts[] = array(
                        'platform_key' => 'linkedin',
                        'platform_label' => 'LinkedIn',
                        'external_account_id' => sanitize_text_field($org_id),
                        'display_name' => sanitize_text_field($org['localizedName'] ?? $org['name']['localized']['en_US'] ?? ('LinkedIn Organization ' . $org_id)),
                        'auth_status' => 'connected',
                        'connection_metadata' => array(
                            'connection_role' => 'organization',
                            'author_urn' => $org_urn,
                        ),
                    );
                }
            }
        }

        return $accounts;
    }

    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 LinkedIn account is required before publishing.');
        }

        $content_item = (array) ($input['content_item'] ?? array());
        $payload = $this->build_base_post_payload($account, $content_item);

        $cta_url = esc_url_raw($content_item['cta_url'] ?? '');
        if ($cta_url !== '') {
            $payload['content'] = array(
                'article' => array(
                    'source' => $cta_url,
                    'title' => sanitize_text_field($content_item['title'] ?? 'VMO Update'),
                    'description' => wp_strip_all_tags($this->get_post_caption($content_item)),
                ),
            );
        }

        $response = $this->linkedin_post('https://api.linkedin.com/rest/posts', $account['access_token'], $payload);
        if (is_wp_error($response)) {
            return $response;
        }

        return array(
            'provider_post_id' => $this->extract_restli_id($response),
            'message' => 'Published to LinkedIn.',
            'response' => $response,
        );
    }

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

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

        $mime = strtolower((string) ($asset['type'] ?? ''));
        if (strpos($mime, 'video/') === 0) {
            return new WP_Error('provider_not_ready', 'LinkedIn video upload is not activated yet in this build.');
        }

        $image_urn = $this->upload_linkedin_image($account, $asset);
        if (is_wp_error($image_urn)) {
            return $image_urn;
        }

        $payload = $this->build_base_post_payload($account, $content_item);
        $payload['content'] = array(
            'media' => array(
                'title' => sanitize_text_field($content_item['title'] ?? $asset['name'] ?? 'VMO Media Post'),
                'id' => $image_urn,
            ),
        );

        $response = $this->linkedin_post('https://api.linkedin.com/rest/posts', $account['access_token'], $payload);
        if (is_wp_error($response)) {
            return $response;
        }

        return array(
            'provider_post_id' => $this->extract_restli_id($response),
            'message' => 'Published media post to LinkedIn.',
            'response' => $response,
        );
    }

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

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

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

    protected function linkedin_headers() {
        return array(
            'X-Restli-Protocol-Version' => '2.0.0',
            'Linkedin-Version' => gmdate('Ym'),
        );
    }

    protected function linkedin_get($url, $access_token, array $query = array()) {
        return $this->api_get($url, $access_token, $query, $this->linkedin_headers());
    }

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

    protected function build_base_post_payload(array $account, array $content_item) {
        $metadata = (array) ($account['connection_metadata'] ?? array());
        return array(
            'author' => sanitize_text_field($metadata['author_urn'] ?? ''),
            'commentary' => $this->get_post_caption($content_item),
            'visibility' => 'PUBLIC',
            'distribution' => array(
                'feedDistribution' => 'MAIN_FEED',
                'targetEntities' => array(),
                'thirdPartyDistributionChannels' => array(),
            ),
            'lifecycleState' => 'PUBLISHED',
            'isReshareDisabledByAuthor' => false,
        );
    }

    protected function upload_linkedin_image(array $account, array $asset) {
        $metadata = (array) ($account['connection_metadata'] ?? array());
        $owner = sanitize_text_field($metadata['author_urn'] ?? '');
        if ($owner === '') {
            return new WP_Error('missing_owner', 'LinkedIn publishing requires a valid member or organization URN.');
        }

        $init = $this->linkedin_post('https://api.linkedin.com/rest/images?action=initializeUpload', $account['access_token'], array(
            'initializeUploadRequest' => array(
                'owner' => $owner,
            ),
        ));
        if (is_wp_error($init)) {
            return $init;
        }

        $upload_url = esc_url_raw($init['value']['uploadUrl'] ?? '');
        $image_urn = sanitize_text_field($init['value']['image'] ?? '');
        if ($upload_url === '' || $image_urn === '') {
            return new WP_Error('provider_api_error', 'LinkedIn image upload did not return an upload URL or image URN.', $init);
        }

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

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

        $upload = wp_remote_request($upload_url, array(
            'method' => 'PUT',
            'timeout' => 120,
            'headers' => array(
                'Authorization' => 'Bearer ' . $account['access_token'],
                'Content-Type' => sanitize_text_field($asset['type'] ?: 'application/octet-stream'),
            ),
            'body' => $binary,
        ));

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

        $status = (int) wp_remote_retrieve_response_code($upload);
        if ($status >= 400) {
            return new WP_Error('provider_api_error', 'LinkedIn image upload failed.', array(
                'status' => $status,
                'response' => wp_remote_retrieve_body($upload),
            ));
        }

        return $image_urn;
    }

    protected function extract_restli_id(array $response) {
        $headers = $response['_response_headers'] ?? array();
        if (is_object($headers) && method_exists($headers, 'getAll')) {
            $headers = $headers->getAll();
        } elseif (is_object($headers)) {
            $headers = (array) $headers;
        }

        foreach (array('x-restli-id', 'X-RestLi-Id', 'X-Restli-Id') as $key) {
            if (!empty($headers[$key])) {
                return sanitize_text_field(is_array($headers[$key]) ? reset($headers[$key]) : $headers[$key]);
            }
        }

        return sanitize_text_field($response['id'] ?? '');
    }
}
