<?php

namespace App\Services\Smm;

use App\Services\Contracts\SmmPlatformInterface;
use Abraham\TwitterOAuth\TwitterOAuth;
use Carbon\Carbon;
use CURLFile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class TwitterService implements SmmPlatformInterface
{
    protected $configData;

    private $clientId;
    private $clientSecret;

    private $access_token;
    private $media_upload_url = 'https://api.x.com/2/media/upload';
    private $tweet_url = 'https://api.x.com/2/tweets';
    private $chunk_size = 4 * 1024 * 1024; // 分块上传的大小，不能大于5M，否则会报错

    public function __construct($configData)
    {
        $this->clientId = env('SSM_X_CLIENT_ID');
        $this->clientSecret = env('SSM_X_CLIENT_SECRET');
        $this->configData = $configData;
    }

    public function login()
    {
        $redirectUri = env('DIST_SITE_URL') . '/dist/callback/twitter';
        $scopes = ['tweet.read','tweet.write','users.read','offline.access','media.write']; // 需要的权限范围
        $oauthState = bin2hex(random_bytes(16));
        $authUrl = 'https://twitter.com/i/oauth2/authorize?' . http_build_query([
                'response_type' => 'code',
                'client_id' => $this->clientId,
                'redirect_uri' => $redirectUri,
                'scope' => implode(' ', $scopes),
                'state' => $oauthState,
                'code_challenge' => 'challenge', // 如果使用 PKCE 需要生成
                'code_challenge_method' => 'plain'
            ]);
        return [
            'status' => true,
            'data' => ['url' => $authUrl]
        ];
    }

    public function loginCallback(Request $request)
    {
        try {
            $tokenUrl = 'https://api.twitter.com/2/oauth2/token';
            $redirectUri = env('DIST_SITE_URL') . '/dist/callback/twitter';
            $params = [
                'code' => $_GET['code'],
                'grant_type' => 'authorization_code',
                'client_id' => $this->clientId,
                'redirect_uri' => $redirectUri,
                'code_verifier' => 'challenge' // 如果使用 PKCE 需要对应
            ];
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $tokenUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret),
                'Content-Type: application/x-www-form-urlencoded'
            ]);
            $auth = curl_exec($ch);
            curl_close($ch);
            $auth = json_decode($auth, true);
            if (isset($auth['access_token']) == false) {
                return ['status' => false, 'data' => '获取token失败'];
            }
            $this->access_token = $auth['access_token'];
            $url = 'https://api.twitter.com/2/users/me?user.fields=id,username,name';
            $result = $this->twitterApiRequest($url, 'GET');
           // var_dump($result);
           // exit;
            if ($result['code'] != 200) {
                return ['status' => false, 'data' => '获取token失败'];
            }


            if (isset($auth['access_token'])) {
                $userData = $result['response']['data'];
                $userId = $userData['id'];
                $username = $userData['username'];
                $name = $userData['name'];

                $refresh_token = $auth['refresh_token'] ?? '';
                $expires_in = $auth['expires_in'] ?? 0;
                $expiresAt = Carbon::now()->addSeconds($expires_in)->format('Y-m-d H:i:s');

                return [
                    'status' => true,
                    'data' => [
                        'accessToken' => $auth['access_token'],
                        'backupField1' => '',
                        'userId' => $userId,
                        'userName' => $username,
                        'accessToken_expiresAt' => $expiresAt,
                        'refreshToken' => $refresh_token,
                    ]
                ];
            } else {
                return ['status' => false, 'data' => '获取token失败'];
            }
        } catch (\Exception $e) {
            return ['status' => false, 'data' => $e->getMessage()];
        }
    }


    public function postImage($message, $imagePaths, $accessToken = null)
    {
        try {
            $this->access_token = $accessToken;
            $videoPaths = [];
            foreach ($imagePaths as $imagePath) {
                $videoPaths[] = toStoragePath($imagePath);//用本地路径上传
            }
            $mediaResult = $this->uploadAndPost($videoPaths, $message);
            if (isset($mediaResult['response']['data']['id'])) {
                return ['status' => true,
                    'data' => [
                        'responseIds' => [$mediaResult['response']['data']['id']],
                    ]
                ];
            } else {
                return ['status' => false, 'data' => $mediaResult['message']];
            }
        } catch (\Exception $e) {
            return ['status' => false, 'data' => $e->getMessage()];
        }
    }


    public function postVideo($message, $videoPath, $accessToken = null)
    {
        try {
            $this->access_token = $accessToken;
            $videoPath = toStoragePath($videoPath);//用本地路径上传
            $mediaResult = $this->uploadAndPost([$videoPath], $message);
            if (isset($mediaResult['response']['data']['id'])) {
                return ['status' => true,
                    'data' => [
                        'responseIds' => [$mediaResult['response']['data']['id']],
                    ]
                ];
            } else {
                return ['status' => false, 'data' => $mediaResult['message']];
            }
        } catch (\Exception $e) {
            return ['status' => false, 'data' => $e->getMessage()];
        }
    }

    // 保持空实现
    public function getComments($postId) {}

    public function replyToComment($commentId) {}

    public function deleteComment($commentId) {}

    /**
     * 通用Twitter API请求
     */
    private function twitterApiRequest($url, $method = 'POST', $data = [], $headers = []) {
        try {
            Log::info('curl 请求:'.$url);
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 不验证对等证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);     // 不验证主机名

            $headers = array_merge([
                'Authorization: Bearer ' . $this->access_token
            ], $headers);

            Log::info('curl $headers:'.json_encode($headers));

            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTPHEADER => $headers,
                CURLOPT_TIMEOUT => 50,
            ]);

            if ($method === 'POST') {
                curl_setopt($ch, CURLOPT_POST, true);

                // 处理JSON数据
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            }

            $response = curl_exec($ch);
            $error = curl_error($ch);
            curl_close($ch);

            Log::info('curl response:'.$response);

            if ($error) {
                throw new \Exception("cURL Error: ".$error);
            }

            if ($response === false) {
                throw new \Exception("cURL Error: false response");
            }

            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

            return ['code'=>$http_code,'response' => json_decode($response, true)];
        } catch (\Exception $e) {
            throw new \Exception("catch cURL Error: ".$e->getMessage());
        }
    }

    /**
     * 初始化上传
     */
    public function initUpload($fileSize, $mediaType = 'video/mp4',$media_category = 'tweet_video') {
        return $this->twitterApiRequest($this->media_upload_url, 'POST', [
            'command' => 'INIT',
            'media_type' => $mediaType,
            'total_bytes' => $fileSize,
            'media_category' => $media_category
        ]);
    }

    /**
     * 分块上传
     */
    public function appendUpload($media_id, $filePath) {
        $handle = fopen($filePath, 'rb');
        $segment_index = 0;

        while (!feof($handle)) {
            $chunk = fread($handle, $this->chunk_size);
            $result = $this->twitterApiRequest($this->media_upload_url, 'POST', [
                'command' => 'APPEND',
                'media_id' => $media_id,
                'segment_index' => $segment_index,
                'media' => $chunk
            ]);

            Log::info('分块上传'.$segment_index.' : '.json_encode($result));

            if ($result['code'] !== 204) {
                return false;
            }
            $segment_index++;
            sleep(2); // 避免速率限制
        }

        fclose($handle);
        return true;
    }

    /**
     * 完成上传
     */
    public function finalizeUpload($media_id) {
        return $this->twitterApiRequest($this->media_upload_url, 'POST', [
            'command' => 'FINALIZE',
            'media_id' => $media_id
        ]);
    }

    /**
     * 检查媒体状态
     */
    public function checkStatus($media_id) {
        $url = $this->media_upload_url . '?' . http_build_query([
                'command' => 'STATUS',
                'media_id' => $media_id
            ]);

        return $this->twitterApiRequest($url, 'GET');
    }

    /**
     * 等待媒体处理完成
     */
    public function waitForProcessing($media_id, $interval = 10, $max_attempts = 6) {
        $attempts = 0;
        do {
            $status = $this->checkStatus($media_id);
            Log::info('等待媒体处理完成:'.$attempts.' : '.json_encode($status));
            if (!isset($status['response']['data'])) {
                throw new \Exception("waitForProcessing failed: status data not found");
            }
            $state = $status['response']['data']['processing_info']['state'] ?? '';

            if ($state === 'succeeded') return true;
            if ($state === 'failed') return false;

            sleep($interval);
            $attempts++;
        } while ($attempts < $max_attempts);

        throw new \Exception("Media processing timeout");
    }

    /**
     * 发布推文
     */
    public function postTweet($text, $media_ids) {
        $data = [
            'text' => $text,
            'media' => ['media_ids' => $media_ids]
        ];
        $data = json_encode($data);
        Log::info('发布推文数据:'.$data);
        return $this->twitterApiRequest($this->tweet_url, 'POST',$data , ['Content-Type: application/json']);
    }

    /**
     * 完整上传流程
     */
    public function uploadAndPost($filePaths, $tweetText) {
        try {
            $tweetText = $this->truncateText($tweetText);// 截断推文

            $media_ids = [];
            foreach ($filePaths as $filePath) {
                $file_info = pathinfo($filePath);
                $file_extension = $file_info['extension'];

                if ($file_extension == 'mp4' && filesize($filePath) > 20 * 1024 * 1024) {
                    //不能大于20M
                    return ['status'=>false,'message' => 'File size too large (max 20M)'];
                } else if (($file_extension == 'jpg' || $file_extension == 'png') && filesize($filePath) > 3 * 1024 * 1024) {
                    //不能大于5M
                    return ['status'=>false,'message' => 'File size too large (max 5M)'];
                }

                if ($file_extension == 'mp4') {
                    $media_category = 'tweet_video';
                    $mediaType = 'video/mp4';
                } else if ($file_extension == 'jpg') {
                    $media_category = 'tweet_image';
                    $mediaType = 'image/jpeg';
                } else {
                    $media_category = 'tweet_image';
                    $mediaType = 'image/png';
                }
                Log::info('Twitter开始发布帖子,文件格式：'.$file_extension);
                // 1. 初始化上传
                $init = $this->initUpload(filesize($filePath),$mediaType,$media_category);
                $media_id = isset($init['response']['data']['id']) ? $init['response']['data']['id'] : null;
                $media_ids[] = $media_id;
                if (!$media_id) {
                    return ['status'=>false,'message' => 'Init upload failed'];
                }
                Log::info('初始化上传成功'.$media_id);

                // 2. 分块上传
                $append = $this->appendUpload($media_id, $filePath);
                if (!$append) {
                    return ['status'=>false,'message' => 'Append upload failed'];
                }

                // 3. 完成上传
                $finalize = $this->finalizeUpload($media_id);
                Log::info('完成上传:'.json_encode($finalize));
                if (isset($finalize['response']['data']) == false) {
                    return ['status'=>false,'message' => 'Finalize upload failed'];
                }

                // 4. mp4 等待处理完成
                if ($file_extension == 'mp4') {
                    Log::info('等待处理完成');
                    if (!$this->waitForProcessing($media_id)) {
                        throw new \Exception('Media processing failed');
                    }
                }
            }

            // 5. 发布推文
            Log::info('发布推文');
            $postTweet = $this->postTweet($tweetText, $media_ids);
            Log::info('发布推文结果:'.json_encode($postTweet));
            return $postTweet;
        } catch (\Exception $e) {
            Log::info('uploadAndPost error:'.$e->getMessage());
            return ['status'=>false,'message' => "Upload failed: ".$e->getMessage()];
        }
    }

    public function refreshAccessToken($refreshToken)
    {
        try {
            $tokenUrl = 'https://api.twitter.com/2/oauth2/token';
            $params = [
                'refresh_token' => $refreshToken,
                'grant_type' => 'refresh_token',
                'client_id' => $this->clientId,
            ];

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $tokenUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret),
                'Content-Type: application/x-www-form-urlencoded'
            ]);

            $response = curl_exec($ch);
            $error = curl_error($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            if ($error) {
                throw new \Exception("cURL Error: " . $error);
            }

            $authData = json_decode($response, true);
            if (!$authData || isset($authData['error'])) {
                throw new \Exception("Token refresh failed: " . ($authData['error_description'] ?? 'Unknown error'));
            }

            if (!isset($authData['access_token'])) {
                throw new \Exception("Access token not found in response");
            }


            $newAccessToken = $authData['access_token'];
            $newRefreshToken = $authData['refresh_token'] ?? $refreshToken; // 使用新的refresh_token，若未返回则保留原值
            $expiresIn = $authData['expires_in'] ?? 0;
            $expiresAt = Carbon::now()->addSeconds($expiresIn)->format('Y-m-d H:i:s');

            return [
                'status' => true,
                'data' => [
                    'access_token' => $newAccessToken,
                    'refresh_token' => $newRefreshToken,
                    'expires_at' => $expiresAt,
                ],
            ];
        } catch (\Exception $e) {
            Log::error("Twitter刷新Token失败: " . $e->getMessage());
            return [
                'status' => false,
                'data' => $e->getMessage(),
            ];
        }
    }



    /**
     * 安全截断多字节文本（按字符宽度计算，支持中文、日文、葡萄牙语等）
     * @param string $text 原始文本
     * @param int $maxWidth 最大显示宽度（默认 280）
     * @param string $ellipsis 截断后缀（默认...）
     * @return string 处理后的文本
     */
    function truncateText(string $text, int $maxWidth = 250, string $ellipsis = ''): string {
        if ($maxWidth <= 0) return '';

        // 计算后缀的显示宽度
        $ellipsisWidth = mb_strwidth($ellipsis, 'UTF-8');

        // 如果后缀宽度已超过最大限制
        if ($ellipsisWidth >= $maxWidth) {
            return mb_strimwidth($ellipsis, 0, $maxWidth, '', 'UTF-8');
        }

        // 允许的文本部分最大宽度
        $allowedWidth = $maxWidth - $ellipsisWidth;

        // 直接检查完整文本宽度
        $textWidth = mb_strwidth($text, 'UTF-8');
        if ($textWidth <= $allowedWidth) {
            return $text . $ellipsis;
        }

        // 精确截断（处理最后字符可能被切断的情况）
        $truncated = mb_strimwidth($text, 0, $allowedWidth, '', 'UTF-8');
        return $truncated . $ellipsis;
    }

}
