<?php

namespace App\Http\Services\Account\Threads;

use App\Traits\AccountManager;
use App\Models\Platform;
use App\Models\SocialAccount;
use App\Models\SocialPost;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;

class Account
{
    use AccountManager;

    public $thUrl, $params;

    const BASE_URL = 'https://www.threads.net';
    const API_URL = 'https://graph.threads.net';

    public function __construct()
    {
        $this->thUrl = "https://www.threads.net/";

        $this->params = [
            'fields' => 'id,username,name,threads_profile_picture_url'
        ];
    }

    /**
     * Summary of authRedirect
     * @param \App\Models\Platform $platform
     * @return string
     */
    public static function authRedirect(Platform $platform)
    {
        $configuration = $platform->configuration;

        $client_id = $configuration->client_id;
        $redirect_uri = url('/account/threads/callback?medium=' . $platform->slug);
        $scope = 'threads_basic threads_content_publish threads_manage_replies threads_read_replies threads_manage_insights';
        $state = 'state123';

        return "https://www.threads.net/oauth/authorize?client_id={$client_id}&redirect_uri={$redirect_uri}&scope={$scope}&response_type=code&state={$state}";
    }



    /**
     * Build API URL
     */
    public static function getApiUrl(string $endpoint, array $params, mixed $configuration, bool $isBaseUrl = false): string
    {
        $apiUrl = $isBaseUrl ? self::BASE_URL : self::API_URL;

        if (str_starts_with($endpoint, '/')) {
            $endpoint = substr($endpoint, 1);
        }

        $version = $configuration->app_version ?? 'v1.0';

        $url = $apiUrl . '/' . $version . '/' . $endpoint;

        if (count($params)) {
            $url .= '?' . http_build_query($params);
        }

        return $url;
    }

    /**
     * Summary of getAccessToken
     * @param string $code
     * @param \App\Models\Platform $platform
     * @return \Illuminate\Http\Client\Response
     */
    public static function getAccessToken(string $code, Platform $platform)
    {
        $configuration = $platform->configuration;

        return Http::asForm()->post("https://graph.threads.net/oauth/access_token", [
            'client_id' => $configuration->client_id,
            'client_secret' => $configuration->client_secret,
            'code' => $code,
            'grant_type' => 'authorization_code',
            'redirect_uri' => url('/account/threads/callback?medium=' . $platform->slug),
        ]);
    }


    public static function getLongLiveToken(string $shortToken, Platform $platform)
    {
        $configuration = $platform->configuration;

        return Http::get("https://graph.threads.net/access_token", [
            'client_secret' => $configuration->client_secret,
            'grant_type' => 'th_exchange_token',
            'access_token' => $shortToken,
        ]);

    }

    /**
     * Refresh token
     */
    public static function refreshAccessToken(Platform $platform, string $token)
    {
        $configuration = $platform->configuration;

        return Http::asForm()->post("https://graph.threads.net/refresh_access_token", [
            'grant_type' => 'th_refresh_token',
            'access_token' => $token,
        ]);
    }

    /**
     * Get logged-in user info
     */
    public function getAcccount(string $token, Platform $platform)
    {
        $configuration = $platform->configuration;

        $apiUrl = self::getApiUrl('me', [
            'fields' => 'id,username,name,threads_profile_picture_url',
            'access_token' => $token
        ], $configuration);

        return Http::get($apiUrl);
    }

    /**
     * Save Threads account
     */
    public static function saveThAccount(
        mixed $responseData,
        string $guard,
        Platform $platform,
        string $account_type,
        string $is_official,
        int|string $dbId = null
    ) {
        $th = new self();

        // Handle both Response object and array
        if (is_array($responseData)) {
            $data = $responseData;
        } elseif (is_object($responseData) && method_exists($responseData, 'json')) {
            $data = $responseData->json();
        } else {
            $data = (array) $responseData;
        }

        $token = Arr::get($data, 'access_token');
        $refresh_token = Arr::get($data, 'refresh_token');

        $response = $th->getAcccount($token, $platform)->throw();
        $user = $response->json();

        $accountInfo = [
            'id' => $user['id'],
            'account_id' => $user['id'],
            'name' => Arr::get($user, 'name') ?? Arr::get($user, 'username'),
            'avatar' => Arr::get($user, 'threads_profile_picture_url'),
            'email' => null,
            'token' => $token,
            'access_token_expire_at' => now()->addMonths(2),
            'refresh_token' => $refresh_token,
            'refresh_token_expire_at' => now()->addMonths(2),
        ];

        return $th->saveAccount($guard, $platform, $accountInfo, $account_type, $is_official, $dbId);
    }

    /**
     * Get post details
     */
    public static function getPost(string $postId, string $token, Platform $platform)
    {
        $configuration = $platform->configuration;

        $apiUrl = self::getApiUrl($postId, [
            'fields' => 'id,caption,media_type,media_url,permalink',
            'access_token' => $token
        ], $configuration);

        return Http::get($apiUrl);
    }

    /**
     * Publish post
     */
    public function send(SocialPost $post): array
    {
        try {
            $account = $post->account;
            $accountToken = $account->token;
            $platform = $account->platform;
            $configuration = $platform->configuration;

            $caption = $post->content ?? '';
            if ($post->link) {
                $caption .= ' ' . $post->link;
            }

            $containerUrl = self::getApiUrl("{$account->account_id}/threads", [], $configuration);

            $payload = [
                'access_token' => $accountToken,
                'text' => $caption,
            ];

            $isVideo = false;

            // Handle media files (images and videos)
            if ($post->files && $post->files->count() > 0) {
                $file = $post->files->first();
                $mediaUrl = imageURL($file, "gallery");

                if (isValidVideoUrl($mediaUrl)) {
                    // Video post
                    $payload['media_type'] = 'VIDEO';
                    $payload['video_url'] = $mediaUrl;
                    $isVideo = true;
                } else {
                    // Image post
                    $payload['media_type'] = 'IMAGE';
                    $payload['image_url'] = $mediaUrl;
                }
            } else {
                // Text-only post
                $payload['media_type'] = 'TEXT';
            }

            // Step 1: Create container
            $container = Http::post($containerUrl, $payload)->json();

            if (!isset($container['id'])) {
                return [
                    'status' => false,
                    'response' => $container['error']['message'] ?? 'Failed to create container',
                ];
            }

            // Step 2: Wait for media processing (required for videos, recommended for images)
            // Videos require longer processing time
            if ($isVideo) {
                // Poll for container status for videos
                $maxAttempts = 30;
                $attempt = 0;
                $isReady = false;

                while ($attempt < $maxAttempts && !$isReady) {
                    sleep(2); // Wait 2 seconds between checks
                    $statusUrl = self::getApiUrl($container['id'], [
                        'fields' => 'status',
                        'access_token' => $accountToken
                    ], $configuration);

                    $statusResponse = Http::get($statusUrl)->json();
                    $status = $statusResponse['status'] ?? '';

                    if ($status === 'FINISHED') {
                        $isReady = true;
                    } elseif (in_array($status, ['ERROR', 'EXPIRED'])) {
                        return [
                            'status' => false,
                            'response' => 'Video processing failed: ' . $status,
                        ];
                    }

                    $attempt++;
                }

                if (!$isReady) {
                    return [
                        'status' => false,
                        'response' => 'Video processing timed out',
                    ];
                }
            } else {
                // For images/text, wait a shorter time
                sleep(3);
            }

            // Step 3: Publish container
            $publishUrl = self::getApiUrl("{$account->account_id}/threads_publish", [], $configuration);
            $publish = Http::post($publishUrl, [
                'creation_id' => $container['id'],
                'access_token' => $accountToken,
            ])->json();

            if (isset($publish['id'])) {
                return [
                    'status' => true,
                    'response' => translate("Posted Successfully"),
                    'url' => "https://www.threads.net/@" . ($account->name ?? $account->account_id) . "/post/" . $publish['id'],
                    'post_id' => $publish['id'],
                ];
            }

            return [
                'status' => false,
                'response' => $publish['error']['message'] ?? 'Failed to publish',
            ];

        } catch (\Exception $ex) {
            return [
                'status' => false,
                'response' => strip_tags($ex->getMessage()),
                'url' => null
            ];
        }
    }



    /**
     * Get account-level insights (followers, etc.)
     *
     * @param SocialAccount $account
     * @return array
     */
    public function getAccountInsights(SocialAccount $account): array
    {
        try {
            $token = $account->token ?? $account->access_token ?? null;

            if (!$token) {
                return [
                    'status' => false,
                    'message' => 'Missing access token',
                    'data' => [],
                ];
            }

            $configuration = $account->platform->configuration ?? null;
            $version = $configuration->app_version ?? 'v1.0';

            // Threads API: Get user insights for followers count
            $apiUrl = "https://graph.threads.net/{$version}/{$account->account_id}/threads_insights";

            $response = Http::withToken($token)
                ->get($apiUrl, [
                    'metric' => 'followers_count',
                ]);

            $data = $response->json();

            if ($response->failed() || isset($data['error'])) {
                // Fallback: try to get basic profile info
                $profileUrl = "https://graph.threads.net/{$version}/me";
                $profileResponse = Http::withToken($token)->get($profileUrl, [
                    'fields' => 'id,username,threads_profile_picture_url,threads_biography',
                ]);

                if ($profileResponse->successful()) {
                    return [
                        'status' => true,
                        'message' => 'Profile fetched (insights unavailable)',
                        'data' => [
                            'followers' => 0, // Insights not available
                        ],
                    ];
                }

                $errorMsg = $data['error']['message'] ?? 'API request failed';
                return [
                    'status' => false,
                    'message' => $errorMsg,
                    'data' => [],
                ];
            }

            $insights = $data['data'] ?? [];
            $followersCount = 0;

            foreach ($insights as $insight) {
                if (($insight['name'] ?? '') === 'followers_count') {
                    $followersCount = $insight['total_value']['value'] ?? $insight['values'][0]['value'] ?? 0;
                    break;
                }
            }

            return [
                'status' => true,
                'message' => 'Account insights fetched successfully',
                'data' => [
                    'followers' => $followersCount,
                ],
            ];

        } catch (\Throwable $e) {
            return [
                'status' => false,
                'message' => 'Error fetching account insights: ' . $e->getMessage(),
                'data' => [],
            ];
        }
    }

    /**
     * Get metrics/insights for a Threads post
     *
     * @param SocialPost $post
     * @param SocialAccount $account
     * @return array
     */
    public function getInsight(SocialPost $post, SocialAccount $account): array
    {
        try {
            $token = $account->token ?? $account->access_token ?? null;

            if (!$token || !$post->platform_post_id) {
                return [
                    'status' => false,
                    'message' => 'Missing access token or post ID',
                    'metrics' => [],
                ];
            }

            $configuration = $account->platform->configuration ?? null;
            $version = $configuration->app_version ?? 'v1.0';

            $apiUrl = "https://graph.threads.net/{$version}/{$post->platform_post_id}/insights";

            // Threads API supported metrics: views, likes, replies, reposts, quotes
            $response = Http::withToken($token)
                ->get($apiUrl, [
                    'metric' => 'views,likes,replies,reposts,quotes',
                ]);

            $data = $response->json();

            if ($response->failed() || isset($data['error'])) {
                $errorMsg = $data['error']['message'] ?? 'API request failed';
                return [
                    'status' => false,
                    'message' => $errorMsg,
                    'metrics' => [],
                ];
            }

            $insights = $data['data'] ?? [];

            // Parse insights by metric name (more reliable than index)
            $parsedMetrics = [];
            foreach ($insights as $insight) {
                $name = $insight['name'] ?? '';
                $value = $insight['values'][0]['value'] ?? 0;
                $parsedMetrics[$name] = $value;
            }

            $views = $parsedMetrics['views'] ?? 0;
            $likes = $parsedMetrics['likes'] ?? 0;
            $replies = $parsedMetrics['replies'] ?? 0;
            $reposts = $parsedMetrics['reposts'] ?? 0;
            $quotes = $parsedMetrics['quotes'] ?? 0;

            $metrics = [
                'impressions' => $views,
                'engagements' => $likes + $replies + $reposts + $quotes,
                'likes' => $likes,
                'comments' => $replies,
                'shares' => $reposts + $quotes,
                'reactions' => $likes,
                'reach' => $views,
            ];

            return [
                'status' => true,
                'message' => 'Metrics fetched successfully',
                'metrics' => $metrics,
            ];

        } catch (\Throwable $e) {
            return [
                'status' => false,
                'message' => 'Error fetching Threads metrics: ' . $e->getMessage(),
                'metrics' => [],
            ];
        }
    }
}
