<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\LinkHistory;
use App\Models\Link;
use App\Models\ReferralCommission;
use App\Models\IpData;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Auth\Events\Verified;
use GuzzleHttp\Client;
use Illuminate\Support\Str;
use Carbon\Carbon;

class LinksController extends Controller
{
    public function __construct()
    {
        $shortlink_status = get_setting('shortlink_status');
        if($shortlink_status == 'off'){
            abort(404, "Not found.");
        }
    }
    public function index(Request $request)
    {
        if (!$request->user()->hasVerifiedEmail()) {
            return redirect('/dashboard')->with('message', 'Please verify your email first')->with('type', 'error');
        }
        $user = Auth::user();
        $page = 'Shortlinks';

        return view('shortlink.links', compact(
            'page'
        ));
    }
    public function advertise()
    {
        $page = 'Advertise Shortlink';

        return view('shortlink.advertise', compact(
            'page'
        ));
    }

    public function fetchAds(Request $request, $status)
    {
        if (!$request->ajax()) {
            return response()->json(['error' => 'Invalid request'], 400);
        }
        $perPage = 10;
        $query = Link::orderBy('created_at', 'desc')->where('user_id', Auth::id())->where('status', $status);
        
        $Ads = $query->paginate($perPage);
        
        $records = $Ads->map(function ($item) {
            return [
                'id' => $item->id,
                'name' => $item->name,
                'url' => $item->api_url,
                'remaining_views' => $item->remaining_views,
                'today_views' => $item->today_views,
                'views' => $item->views,
            ];
        });
        
        return response()->json([
            'records' => $records,
            'current_page' => $Ads->currentPage(),
            'total_pages' => $Ads->lastPage(),
            'prev_page' => $Ads->previousPageUrl() ? $Ads->currentPage() - 1 : null,
            'next_page' => $Ads->nextPageUrl() ? $Ads->currentPage() + 1 : null,
        ]);
    }
    public function redirect(Request $request, $id)
    {
        $user = Auth::user();
        $ip = $request->ip();
        
        $link = Link::where('id', $id)
            ->where(function ($query) {
                $query->where('user_id', 0)
                      ->orWhere(function ($q) {
                          $q->where('user_id', '!=', 0)
                            ->where('status', 1);
                      });
            })
            ->where(function ($query) {
                $query->where('countries', '*')
                      ->orWhereRaw("FIND_IN_SET(?, countries)", [Auth::user()->country]);
            })
            ->first();
        
        if (!$link) {
            return redirect('/links')->with('message', 'Shortlink not found.')->with('type', 'error');
        }
        
        $claims = LinkHistory::where('link_id', $id)
            ->where(function ($query) use ($user, $ip) {
                $query->where('ip', $ip)
                      ->orWhere('user_id', $user->id);
            })
            ->where('created_at', '>=', Carbon::now()->subDay())
            ->count();
        
        if ($claims >= $link->limit) {
            return redirect('/links')->with('message', 'Limit Reached.')->with('type', 'error');
        }
    
        if ($request->isMethod('post')) {
            if (!session()->has('cdata')) {
                return redirect()->back()->with('message', 'The captcha verification failed. Please try again.')->with('type', 'error');
            }
        
            $functionData = session('cdata');
            $captchaResponse = $request->input($functionData['ctoken']);
            $isVerified = verify_ccaptcha($functionData, $captchaResponse);
        
            if (!$isVerified) {
                return redirect()->back()->with('message', 'The captcha verification failed. Please try again.')->with('type', 'error');
            }
            $client = new Client();

            $token = Str::random(33);
            $backUrl = url('/link/back/'.$token);
        
            try {
                $response = $client->get($link->api_url.$backUrl);
        
                $result = json_decode($response->getBody(), true);
        
                if (isset($result["status"]) && $result["status"] === 'error') {
                    return redirect()->back()->with('message', $result["message"])->with('type', 'error');
                } 
                
                session(['redirect_token' => [
                    'key' => $token,
                    'link_id' => $id
                ]]);
        
                return redirect()->away($result["shortenedUrl"]);
            } catch (\Exception $e) {
                return redirect()->back()->with('message', 'Failed to shorten URL.')->with('type', 'error');
            }
        }
    
        $page = 'Redirect Validation';
        return view('shortlink.redirect', compact('page', 'link'));
    }

    public function load(Request $request)
    {
        $user = Auth::user();
        $ip = $request->ip();
    
        $availableLinks = Link::where(function ($query) {
                $query->where('user_id', 0)
                      ->orWhere(function ($q) {
                          $q->where('user_id', '!=', 0)
                            ->where('status', 1);
                      });
            })
            ->where(function ($query) {
                $query->where('countries', '*')
                      ->orWhereRaw("FIND_IN_SET(?, countries)", [Auth::user()->country]);
            })
            ->orderByDesc('reward')
            ->get();
    
        $history = LinkHistory::where(function ($query) use ($ip, $user) {
            $query->where('ip', $ip)->orWhere('user_id', $user->id);
        })->where('created_at', '>=', Carbon::now()->subDay())->get();
    
        $totalReward = 0;
    
        foreach ($availableLinks as $link) {
            $countHistory = $history->where('link_id', $link->id)->count();
    
            $link->remaining = max(0, $link->limit - $countHistory);
    
            $totalReward += $link->remaining * $link->reward;
        }
    
        $availableLinks = $availableLinks->sortByDesc('reward')->values();
    
        $countAvailableLinks = Link::count() - $history->count();
    
        foreach ($availableLinks as $item) {
            if (isset($item->reward)) {
                $item->reward = balanceAndSymbol($item->reward);
            }
            if (isset($item->api_url)) {
                $item->api_url = url('/link/go/'.$item->id);
            }
        }
    
        return response()->json([
            'success' => true,
            'data' => $availableLinks ?? []
        ]);
    }

    public function fetchHistory(Request $request)
    {
        if (!$request->ajax()) {
            return response()->json(['error' => 'Invalid request'], 400);
        }
        $perPage = 10;
        $query = LinkHistory::orderBy('created_at', 'desc')->where('user_id', Auth::id());
    
        $LinkHistory = $query->paginate($perPage);
    
        $records = $LinkHistory->map(function ($item) {
            return [
                'name' => $item->name,
                'ip' => $item->ip,
                'reward' => '<span class="flex items-center">
                    <i class="fa fa-plus text-xs mr-1 text-success"></i> ' . balanceAndSymbol($item->reward) . '
                  </span>',
                'date' => $item->updated_at->diffForHumans(),
            ];
        });
    
        return response()->json([
            'records' => $records,
            'current_page' => $LinkHistory->currentPage(),
            'total_pages' => $LinkHistory->lastPage(),
            'prev_page' => $LinkHistory->previousPageUrl() ? $LinkHistory->currentPage() - 1 : null,
            'next_page' => $LinkHistory->nextPageUrl() ? $LinkHistory->currentPage() + 1 : null,
        ]);
    }
    
    public function back(Request $request, $token)
    {
        if (!session()->has('redirect_token')) {
            return redirect('/links')->with('message', 'Invalid Token')->with('type', 'error');
        }
        $sesToken = session('redirect_token');
        if ($sesToken['key'] != $token) {
            return redirect('/links')->with('message', 'Invalid Token')->with('type', 'error');
        }
        $link = Link::find($sesToken['link_id']);
        
        if (!$link) {
            return redirect('/links')->with('message', 'Shortlink not found.')->with('type', 'error');
        }
        
        $userId = Auth::id();
        $ip = $request->ip();
        $reward = $link['reward'];
        $referral = get_setting('referral');
        
        $service = get_setting('lookup_service');

        $cacheKey = "ip_lookup_{$service}_{$ip}";
        
        $ipData = Cache::remember($cacheKey, now()->addHours(6), function () use ($ip, $service) {
            return IpData::where('ip', $ip)->where('api_service', $service)->first();
        });
        
        $country = "";
        if($ipData) {
            $country = $ipData->country_code;
        }
        
        $user = Auth::user();
        $user->earn($reward);
        $user->updateLastActivity();
        $user->detectAndMarkMultiAccount();
        
        LinkHistory::create([
            'user_id' => $user->id,
            'link_id' => $link['id'],
            'owner' => $link['user_id'],
            'name' => $link['name'],
            'reward' => $reward,
            'ip' => $ip,
            'country' => $country,
        ]);
        if($link->user_id != 0) {
            $link->remaining_views = max(0, $link->remaining_views - 1);
        }
        
        $link->today_views += 1;
        $link->views += 1;
    
        if ($link->remaining_views <= 0) {
            $link->status = 3;
        }
    
        $link->save();
        
        if ($user->referred_by != 0) {
            $referrer = User::find($user->referred_by);
            
            if ($referrer) {
                $commission = ($reward * $referral) / 100;
                if($commission > 0) {
                    $referrer->earn($commission);
            
                    ReferralCommission::create([
                        'referrer_id' => $referrer->id,
                        'referred_id' => $user->id,
                        'amount' => $commission,
                        'type' => 'shortlink',
                        'ip_address' => $ip,
                    ]);
                }
            }
        }
        session()->forget('redirect_token');
        return redirect('/links')->with('message', 
            '<div style="display: flex; align-items: center; justify-content: center; text-align: center; gap: 5px;">' . 
            balanceAndSymbol($reward) . 
            '<span>added to your balance!</span></div>'
        )->with('type', 'success');

    }
    public function store(Request $request)
    {
        try {
            $validated = $request->validate([
                'name' => 'required|string|max:100',
                'url' => 'required|url',
                'countries' => 'nullable|array',
                'reward' => 'required|numeric|min:0',
                'views' => 'required|numeric|min:1',
                'limit_per_day' => 'required|integer|min:1',
                'select_all' => 'nullable|integer|in:0,1',
            ]);
            
            $countries = $request->select_all == 1 ? '*' : (is_array($request->countries) ? implode(',', $request->countries) : '*');
            
            $user = auth()->user();
            $link_min_reward = get_setting('link_min_reward')/get_setting('currency_rate');
            $link_minimum_limit = get_setting('link_minimum_limit');
            $fee = get_setting('link_fee');
            
            if ($validated['reward'] < $link_min_reward) {
                return redirect('/advertise/link')->with('message', "Minimum Reward is ".balanceAndSymbol($link_min_reward))->with('type', 'error');
            }
            
            if ($validated['views'] < $link_minimum_limit) {
                return redirect('/advertise/link')->with('message', "Minimum views required: $link_minimum_limit.")->with('type', 'error');
            }
            
            if ($validated['limit_per_day'] > $validated['views']) {
                return redirect('/advertise/link')->with('message', 'Daily limit cannot exceed total views.')->with('type', 'error');
            }
            
            $reward = $validated['reward'] / get_setting('currency_rate');
            $TotalPrice = $validated['views'] * $reward;
            
            $feeAmount = ($TotalPrice * $fee) / 100;
            $TotalPrice += $feeAmount;
            
            if ($user->available_deposit < $TotalPrice) {
                return redirect('/advertise/link')->with('message', 'Insufficient balance.')->with('type', 'error');
            }

            $client = new Client();
            
            $token = Str::random(33);
            $backUrl = url('/link/back/'.$token);
            
            try {
                $response = $client->get($validated['url'].$backUrl);
            
                $result = json_decode($response->getBody(), true);
            
                if (!isset($result["status"])) {
                    throw new \Exception('Failed to shorten URL: Invalid Api URL');
                }
            
                if ($result["status"] === 'error') {
                    return redirect()->back()->with('message', $result["message"])->with('type', 'error');
                } 
            } catch (\Exception $e) {
                return redirect()->back()->with('message', $e->getMessage())->with('type', 'error');
            }

            $user->available_deposit -= $TotalPrice;
            $user->save();
            
            Link::create([
                'user_id' => Auth::id(),
                'name' => $validated['name'],
                'api_url' => $validated['url'],
                'countries' => $countries,
                'remaining_views' => $validated['views'],
                'reward' => $reward,
                'limit' => $validated['limit_per_day'],
                'status' => 0,
            ]);
    
            return redirect()->back()->with('message', 'Ad created successfully!')->with('type', 'success');
        } catch (\Illuminate\Validation\ValidationException $e) {
            $errorMessages = implode(', ', $e->validator->errors()->all());
    
            return redirect()->back()
                ->withErrors($e->validator)
                ->with('message', 'Validation failed! Errors: ' . $errorMessages)
                ->with('type', 'danger');
        }
    }
}
