<?php

namespace App\Http\Controllers\Core;

use App\Enums\AccountType;
use App\Enums\AiModuleType;
use App\Enums\ConnectionType;
use App\Enums\PlanDuration;
use App\Enums\PostStatus;
use App\Enums\StatusEnum;
use App\Enums\SubscriptionStatus;
use App\Http\Requests\LicenseRequest;
use App\Http\Services\Account\Facebook\Account as FacebookAccount;
use App\Http\Services\Account\Instagram\Account as InstagramAccount;
use App\Http\Services\Account\Linkedin\Account as LinkedinAccount;
use App\Http\Services\Account\Twitter\Account as TwitterAccount;
use App\Http\Services\Account\Tiktok\Account as TiktokAccount;
use App\Http\Services\Account\Youtube\Account as YoutubeAccount;
use App\Http\Services\Account\Threads\Account as ThreadsAccount;
use App\Http\Services\Core\DemoService;
use App\Http\Services\UserService;
use App\Http\Utility\SendNotification;
use App\Http\Utility\SendSMS;
use App\Jobs\SendMailJob;
use App\Jobs\SendSmsJob;
use App\Models\Admin\Category;
use App\Models\Admin\Currency;
use App\Models\AiTemplate;
use App\Models\Core\Language;
use App\Models\Core\Setting;
use App\Models\Platform;
use App\Models\Package;
use App\Models\PostWebhookLog;
use App\Models\SocialAccount;
use App\Models\SocialPost;
use App\Models\Subscriber;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Http\Request;
use Gregwar\Captcha\CaptchaBuilder;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Gregwar\Captcha\PhraseBuilder;
use Illuminate\Http\RedirectResponse;
use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Closure;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Storage;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Route;
use Intervention\Image\Facades\Image;
use App\Traits\PostManager;
use App\Traits\AccountManager;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\View\View as ViewView;
use App\Http\Controllers\Controller;
use Intervention\Image\ImageManager;

class CoreController extends Controller
{


    use AccountManager, PostManager;






    public function accessDenied(): ViewView
    {

        return view('access_denied');

    }


    /**
     * change  language
     *
     * @param string $code
     * @return RedirectResponse
     */
    public function languageChange(string $code): RedirectResponse
    {

        if (!Language::where('code', $code)->exists())
            $code = 'en';
        optimize_clear();
        session()->put('locale', $code);
        app()->setLocale($code);

        return back()->with("success", translate('Language Switched Successfully'));
    }






    /**
     * create default image
     *
     * @param string $size
     * @return Response
     */
    public function defaultImageCreate(string $size): Response
    {
        [$width, $height] = explode('x', $size);

        $manager = new ImageManager(\Intervention\Image\Drivers\Gd\Driver::class);

        $image = $manager->create($width, $height)
            ->fill('#ccc');

        $text = $width . 'X' . $height;
        $fontSize = ($width > 100 && $height > 100) ? 60 : 20;

        $image->text(
            $text,
            $width / 2,
            $height / 2,
            function ($font) use ($fontSize) {
                $font->filename(realpath('assets/font') . DIRECTORY_SEPARATOR . 'RobotoMono-Regular.ttf');
                $font->size($fontSize);
                $font->color('#000');
                $font->align('center');
                $font->valign('middle');
            }
        );

        return new Response($image->encodeByExtension('png'), 200, [
            'Content-Type' => 'image/png',
        ]);
    }


    /**
     * @param int|string $randCode
     * @return void
     */
    public function defaultCaptcha(int|string $randCode): void
    {

        $phrase = new PhraseBuilder;
        $code = $phrase->build(4);
        $builder = new CaptchaBuilder($code, $phrase);
        $builder->setBackgroundColor(220, 210, 230);
        $builder->setMaxAngle(25);
        $builder->setMaxBehindLines(0);
        $builder->setMaxFrontLines(0);
        $builder->build($width = 100, $height = 40, $font = null);
        $phrase = $builder->getPhrase();

        if (Session::has('gcaptcha_code')) {
            Session::forget('gcaptcha_code');
        }
        Session::put('gcaptcha_code', $phrase);
        header("Cache-Control: no-cache, must-revalidate");
        header("Content-Type:image/jpeg");
        $builder->output();
    }

    public function clear(): RedirectResponse
    {

        optimize_clear();
        return back()->with(response_status("Cache Clean Successfully"));
    }

    /**
     * Process cron job
     *
     * @return void
     */
    public function cron(): void
    {
        try {

            $this->handleSchedulePost();
            $this->refreshToken();
            $this->getPostMetrics();

        } catch (\Throwable $th) {

        }

        Setting::updateOrInsert(
            ['key' => 'last_cron_run'],
            ['value' => Carbon::now()]
        );
    }



    public function refreshToken(): void
    {

        $dateTime = now()->addDay()->format('Y-m-d h:i:s');


        $accounts = SocialAccount::with(['platform'])
            ->where('access_token_expire_at', '<=', $dateTime)
            ->lazyById(1000, 'id')
            ->each(function (SocialAccount $account) use ($dateTime) {

                $platform = $account?->platform;
                $token = $account?->refresh_token ?? $account?->token;
                if ($platform) {

                    $class = 'App\\Http\\Services\\Account\\' . $platform->slug . '\\Account';

                    $response = $class::refreshAccessToken($platform, $token);



                    if ($response->successful()) {



                        if ($platform->slug == 'facebook' || $platform->slug == 'instagram') {

                            $responseData = $response->json();
                            $accessToken = Arr::get($responseData, 'access_token');

                            $account->token = $accessToken;
                            $account->access_token_expire_at = now()->addMonths(2);

                        } else if ($platform->slug == 'twitter') {


                            $responseData = $response->json();
                            $token = Arr::get($responseData, 'access_token');
                            $refresh_token = Arr::get($responseData, 'refresh_token');

                            $account->token = $token;
                            $account->access_token_expire_at = now()->addMonths(2);
                            $account->refresh_token = $refresh_token;
                            $account->refresh_token_expire_at = now()->addMonths(2);

                        } else if ($platform->slug == 'linkedin') {

                            $responseData = $response->json();

                            $accessToken = Arr::get($responseData, 'access_token');
                            $refreshToken = Arr::get($responseData, 'refresh_token');

                            $account->token = $accessToken;
                            $account->access_token_expire_at = now()->seconds($responseData['expires_in']);
                            $account->refresh_token = $refreshToken;
                            $account->refresh_token_expire_at = now()->seconds($responseData['refresh_token_expires_in']);
                        }
                        $account->save();
                    }
                }

            });



    }



    /**
     * Handle schedule post
     *
     * @return void
     */
    public function handleSchedulePost(): void
    {

        $posts = SocialPost::with(['file'])
            ->postable()
            ->cursor();

        foreach ($posts->chunk(20) as $chunkPosts) {
            foreach ($chunkPosts as $post) {
                sleep(1);

                if (
                    $post->schedule_time <= Carbon::now() ||
                    $post->status == strval(
                        PostStatus::value('PENDING', true)
                    )
                ) {
                    $this->publishPost($post);
                }
            }
        }




    }


    public function getPostMetrics(): void
    {
        SocialPost::where('status', 'published')
            ->whereNotNull('platform_post_id')
            ->with(['account', 'platform'])
            ->chunk(50, function ($posts) {
                foreach ($posts as $post) {
                    $this->updatePostMetrics($post);
                }
            });
    }





    /** security control */
    public function security(): View
    {

        if (
            site_settings('dos_prevent') == StatusEnum::true->status() &&
            !session()->has('dos_captcha')
        ) {

        }
        abort(403);
    }









    /**
     * @param Request $request
     * @param string $guard
     * @param string $medium
     * @param string|null $type
     * @return mixed
     */
    public function redirectAccount(Request $request, string $medium, string $type = null)
    {

        session()->put("guard", 'web');

        $platform = Platform::where('slug', $medium)->firstOrfail();

        switch ($platform->slug) {
            case 'facebook':
                return redirect(FacebookAccount::authRedirect($platform));
            case 'instagram':
                return redirect(InstagramAccount::authRedirect($platform));
            case 'twitter':
                return redirect(TwitterAccount::authRedirect($platform));
            case 'linkedin':
                return redirect(LinkedinAccount::authRedirect($platform));
            case 'tiktok':
                return redirect(TiktokAccount::authRedirect($platform));
            case 'youtube':
                return redirect(YoutubeAccount::authRedirect($platform));
            case 'threads':
                return redirect(ThreadsAccount::authRedirect($platform));

            default:

                break;
        }


    }


    /**
     * @return RedirectResponse
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function handleAccountCallback($medium = null): RedirectResponse
    {
        
        try {
            $platformSlug = request()->input('medium') ?? $medium;
            $code = request()->input('code');
            $guard = session()->get('guard');
            
            if (!$guard || !auth()->guard($guard)->check()) {
                abort(403, "Unauthenticated user request");
            }
            
            if (!$code) {
                abort(403, "Something went wrong, please try again.");
            }
            $platform = Platform::where('slug', $platformSlug)->firstOrFail();
            $routeName = "user.platform.account.index";
            
            switch ($platform->slug) {

                case 'facebook':
                    $token = FacebookAccount::getAccessToken($code, $platform)->throw()->json('access_token');
                    $pages = FacebookAccount::getPagesInfo(
                        ['name,username,picture,access_token'],
                        $platform,
                        $token
                    )
                        ->throw()
                        ->json('data');

                    FacebookAccount::saveFbAccount($pages, $guard, $platform, AccountType::PAGE->value, ConnectionType::OFFICIAL->value);
                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));

                case 'instagram':



                    $token = InstagramAccount::getAccessToken($code, $platform)->throw()->json('access_token');
                    $pages = InstagramAccount::getAccounts(
                        ['connected_instagram_account,name,access_token'],
                        $platform,
                        $token
                    )
                        ->throw()
                        ->json('data');

                    InstagramAccount::saveIgAccount(
                        $pages,
                        $guard,
                        $platform,
                        AccountType::PAGE->value,
                        ConnectionType::OFFICIAL->value,
                        $token,
                    );

                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));



                case 'twitter':
                    $response = TwitterAccount::getAccessToken($code, $platform)->throw();
                    
                    $token = Arr::get($response->json(), 'access_token');
                    
                    TwitterAccount::saveTwAccount(
                        $response->json(),
                        $guard,
                        $platform,
                        AccountType::PROFILE->value,
                        ConnectionType::OFFICIAL->value,
                    );


                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));


                case 'linkedin':

                    $getAccessTokenResponse = LinkedinAccount::getAccessToken($code, $platform);
                    $tokenResponse = $getAccessTokenResponse->json();


                    $accessToken = @$tokenResponse['access_token'] ?? null;


                    if ($getAccessTokenResponse->failed() || !$accessToken) {

                        return redirect()->route($routeName, )
                            ->with(response_status('Failed to connect', 'error'));
                    }

                    $tokenExpireIn = @$tokenResponse['expires_in'] ?? null;


                    $linkedInAccount = LinkedinAccount::getAccount($accessToken, $platform);

                    if ($linkedInAccount->failed()) {

                        return redirect()->route($routeName, )
                            ->with(response_status('Failed to connect', 'error'));

                    }

                    $user = $linkedInAccount->json();


                    LinkedinAccount::saveLdAccount(
                        $user,
                        $guard,
                        $platform,
                        AccountType::PROFILE->value,
                        ConnectionType::OFFICIAL->value,
                        $accessToken,
                        $tokenExpireIn
                    );




                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));

                case "tiktok":
                    $response = TikTokAccount::getAccessToken($code, $platform)->throw();
                    $tokenResponse = $response->json();
                    $accessToken = Arr::get($tokenResponse, 'access_token');


                    TikTokAccount::saveTtAccount(
                        $response,
                        $guard,
                        $platform,
                        AccountType::PROFILE->value,
                        ConnectionType::OFFICIAL->value
                    );

                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));

                case "youtube":
                    // Get state parameter for PKCE code_verifier retrieval
                    $state = request()->input('state');
                    $response = YouTubeAccount::getAccessToken($code, $platform, $state)->throw();
                    $tokenResponse = $response->json();
                    $accessToken = Arr::get($tokenResponse, 'access_token');

                    YouTubeAccount::saveYtAccount(
                        $response,
                        $guard,
                        $platform,
                        AccountType::PROFILE->value,
                        ConnectionType::OFFICIAL->value
                    );

                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));

                case "threads":
                    $cleanCode = preg_replace('/#_.*/', '', $code);
                    $response = ThreadsAccount::getAccessToken($cleanCode, $platform)->throw();
                    $tokenResponse = $response->json();
                    $accessToken = Arr::get($tokenResponse, 'access_token');
                    $lt_response = ThreadsAccount::getLongLiveToken($accessToken, $platform);
                    $longTokenResponse = $lt_response->json();
                    $longLiveToken = Arr::get($longTokenResponse, 'access_token');


                    ThreadsAccount::saveThAccount(
                        $longTokenResponse,
                        $guard,
                        $platform,
                        AccountType::PROFILE->value,
                        ConnectionType::OFFICIAL->value
                    );

                    return redirect()->route($routeName, ['platform' => $platform->slug])
                        ->with(response_status("Account Added"));


                default:

                    break;
            }

            return redirect()->route($routeName, ['platform' => $platform->slug])
                ->with(response_status("Account Added"));





        } catch (\Exception $e) {

            // $routeName = $guard == 'admin' ? "admin.social.account.list" : "user.social.account.list";
            // if (@$platform) {
            //     return redirect()->route($routeName)
            //         ->with(response_status($e->getMessage(), 'error'));
            // }

            abort(403, "Something went wrong, please try again.");
        }


    }



    public function maintenanceMode(): View|RedirectResponse
    {


        $title = translate('Maintenance Mode');

        if (site_settings('maintenance_mode') == (StatusEnum::false)->status())
            return redirect()->route('home');

        return view('maintenance_mode', [
            'title' => $title,
        ]);

    }


    /**
     * Summary of domainNotVerified
     * @return View|\Illuminate\Contracts\View\Factory
     */
    public function domainNotVerified()
    {
        $title = translate('Domain Verification failed');

        return view('domain_not_verified', [
            'title' => $title,
        ]);

    }



    public function checkLicense(LicenseRequest $request)
    {
        $current_time = Carbon::now();

        try {
            $params = [
                'domain' => url('/'),
                'software_id' => config('installer.software_id'),
                'version' => $request->input('version', ''),
                'purchase_key' => $request->input('purchase_key'),
                'envato_username' => $request->input('username'),
            ];

            $url = 'https://verifylicense.online/api/licence-verification/check-domain';
            $response = Http::timeout(120)->post($url, $params);

            Setting::updateOrInsert(
                ['key' => 'next_verification'],
                ['value' => $current_time->addDays(3)]
            );


            if ($response->successful() && ($apiResponse = $response->json()) && ($apiResponse['success'] ?? false) && ($apiResponse['code'] ?? null) === 200) {


                Setting::updateOrInsert(
                    ['key' => 'is_domain_verified'],
                    ['value' => StatusEnum::true->status()]
                );

                Setting::updateOrInsert(
                    ['key' => 'domain_verified_at'],
                    ['value' => $current_time]
                );

                update_env('PURCHASE_KEY', $request->input('purchase_key'));
                update_env('ENVATO_USERNAME', $request->input('username'));

                optimize_clear();
                return redirect()->route('home')->with('success', 'Domain is verified');
            }

            Setting::updateOrInsert(['key' => 'is_domain_verified'], ['value' => StatusEnum::false->status()]);

            return back()->with('error', $data['data']['error'] ?? 'Invalid Domain');

        } catch (\Exception $ex) {

            Setting::updateOrInsert(['key' => 'is_domain_verified'], ['value' => StatusEnum::false->status()]);
            return back()->with('error', 'Domain verification failed.');
        }

    }



    /**
     * Handle post webhook
     *
     */
    public function postWebhook()
    {


        $hubToken = request()->query('hub_verify_token');
        $apiKey = site_settings("webhook_api_key");
        $isUserToken = User::whereNotNull('webhook_api_key')->where('webhook_api_key', $hubToken)->exists();


        if ($apiKey == $hubToken || $isUserToken)
            return response(request()->query('hub_challenge'));


        $user = User::where('uid', request()->input('uid'))->first();

        PostWebhookLog::create([
            'user_id' => $user ? $user->id : null,
            'webhook_response' => request()->all()
        ]);

    }

    public function processImages(Request $request)
    {
        $request->validate([
            'urls' => 'required|array',
            'urls.*' => 'required|url'
        ]);

        $imageUrls = $request->input('urls');
        $results = [];

        foreach ($imageUrls as $index => $imageUrl) {
            try {

                $imageContent = @file_get_contents($imageUrl);

                $contentType = 'image/png';

                $fileName = basename(parse_url($imageUrl, PHP_URL_PATH));
                $fileName = preg_replace('/\?.*/', '', $fileName) ?: 'image_' . ($index + 1) . '.png';

                $base64Content = base64_encode($imageContent);

                $results[] = [
                    'url' => $imageUrl,
                    'filename' => $fileName,
                    'content_type' => $contentType,
                    'content' => $base64Content
                ];
            } catch (\Exception $e) {
                $results[] = [
                    'url' => $imageUrl,
                    'error' => 'Error fetching image: ' . $e->getMessage()
                ];
            }
        }

        return response()->json($results);

    }


    public function processVideos(Request $request)
    {

        $request->validate([
            'urls' => 'required|array',
            'urls.*' => 'required|url'
        ]);

        $videoUrls = $request->input('urls');
        $results = [];


        foreach ($videoUrls as $index => $videoUrl) {
            try {
                $videoContent = @file_get_contents($videoUrl);
                if ($videoContent === false) {
                    throw new \Exception('Failed to fetch video content');
                }

                $contentType = 'video/mp4';

                $fileName = basename(parse_url($videoUrl, PHP_URL_PATH));
                $fileName = preg_replace('/\?.*/', '', $fileName) ?: 'video_' . ($index + 1) . '.mp4';

                $base64Content = base64_encode($videoContent);

                $results[] = [
                    'url' => $videoUrl,
                    'filename' => $fileName,
                    'content_type' => $contentType,
                    'content' => $base64Content
                ];
            } catch (\Exception $e) {
                $results[] = [
                    'url' => $videoUrl,
                    'error' => 'Error fetching video: ' . $e->getMessage()
                ];
            }
        }

        return response()->json($results);

    }



}
