<?php

namespace App\Http\Controllers\Frontend\Streamer;

use App\Http\Controllers\Controller;
use App\Models\Streamer;
use App\Models\User;
use App\Services\Api\API;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;

class StreamerController extends Controller
{
    protected API $api;

    public function __construct(API $api)
    {
        $this->api = $api;
    }

    public function index()
    {
        $user = Auth::user();

        // Check if user already has a streamer account or pending request
        $existingStreamer = Streamer::where('user_id', $user->ID)->first();

        // Get user's characters
        $characters = $this->getUserCharacters($user->ID);

        // Get registration open setting
        $registrationOpen = DB::table('settings')
            ->where('key', 'streamer_registration_open')
            ->first();
        $isRegistrationOpen = $registrationOpen ? $registrationOpen->value === '1' : true;
        $streamerCodeUsage = $existingStreamer ? [
            'code' => $existingStreamer->code,
            'total_usage' => $this->getStreamerCodeUsageCount($existingStreamer->code),
        ] : null;
        $streamerCodeUsageHistory = $existingStreamer && $existingStreamer->status === 'approved'
            ? $this->getStreamerCodeUsageHistory($existingStreamer->code)
            : [];

        return Inertia::render('frontend/streamer/index', [
            'user' => [
                'id' => $user->ID,
                'name' => $user->name,
                'truename' => $user->truename,
            ],
            'characters' => $characters,
            'existingRequest' => $existingStreamer ? [
                'id' => $existingStreamer->id,
                'status' => $existingStreamer->status,
                'code' => $existingStreamer->code,
                'discord_id' => $existingStreamer->discord_id,
                'channel_link' => $existingStreamer->channel_link,
                'character_id' => $existingStreamer->character_id,
                'requested_at' => $existingStreamer->requested_at,
                'processed_at' => $existingStreamer->processed_at,
            ] : null,
            'registrationOpen' => $isRegistrationOpen,
            'streamerCodeUsage' => $streamerCodeUsage,
            'streamerCodeUsageHistory' => $streamerCodeUsageHistory,
        ]);
    }

    public function store(Request $request)
    {
        $user = Auth::user();

        // Check if registration is open
        $registrationOpen = DB::table('settings')
            ->where('key', 'streamer_registration_open')
            ->first();
        $isRegistrationOpen = $registrationOpen ? $registrationOpen->value === '1' : true;

        if (! $isRegistrationOpen) {
            return back()->withErrors([
                'message' => 'Streamer registration is currently closed. Please try again later.',
            ]);
        }

        // Check if user already has a streamer account or pending request
        $existingStreamer = Streamer::where('user_id', $user->ID)->first();
        if ($existingStreamer) {
            return back()->withErrors([
                'message' => 'You already have a streamer request. Status: '.$existingStreamer->status,
            ]);
        }

        $validated = $request->validate([
            'discord_id' => 'required|string|max:255',
            'code' => 'required|string|max:50|unique:streamers,code',
            'channel_link' => 'required|url|max:500',
        ]);

        // Create streamer request
        Streamer::create([
            'user_id' => $user->ID,
            'code' => strtoupper($validated['code']),
            'discord_id' => $validated['discord_id'],
            'channel_link' => $validated['channel_link'],
            'percentage' => 0, // Will be set by admin on approval
            'status' => 'pending',
            'is_active' => false, // Will be activated on approval
            'requested_at' => now(),
        ]);

        return back()->with('success', 'Your streamer request has been submitted successfully! Please wait for admin approval.');
    }

    /**
     * Upload an image for approved streamers
     */
    public function upload(Request $request)
    {
        $user = Auth::user();

        // Check if user is an approved streamer
        $streamer = Streamer::where('user_id', $user->ID)
            ->where('status', 'approved')
            ->where('is_active', true)
            ->first();

        if (! $streamer) {
            return back()->withErrors([
                'message' => 'Only approved and active streamers can upload images.',
            ]);
        }

        // Validate the upload
        $validated = $request->validate([
            'image' => 'required|image|mimes:jpeg,jpg,png,gif,webp|max:5120', // 5MB max
        ]);

        // Check daily upload limit (1 upload per day)
        $todayUploadsCount = $streamer->uploads()
            ->whereDate('created_at', today())
            ->count();

        if ($todayUploadsCount >= 1) {
            return back()->withErrors([
                'message' => 'You have reached the daily upload limit of 1 image.',
            ]);
        }

        // Store the image
        $path = $request->file('image')->store('streamer-uploads', 'public');

        // Create upload record
        $upload = \App\Models\StreamerUpload::create([
            'streamer_id' => $streamer->id,
            'image_path' => $path,
            'status' => 'pending',
        ]);

        // Send Discord notification if webhook is configured
        $this->sendDiscordNotification($streamer, $upload);

        return back()->with('success', 'Image uploaded successfully! Waiting for admin approval.');
    }

    /**
     * Get streamer's upload history
     */
    public function getUploads()
    {
        $user = Auth::user();

        $streamer = Streamer::where('user_id', $user->ID)->first();

        if (! $streamer) {
            return response()->json(['uploads' => []]);
        }

        $uploads = $streamer->uploads()
            ->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($upload) {
                return [
                    'id' => $upload->id,
                    'image_url' => $upload->image_url,
                    'status' => $upload->status,
                    'gold_reward' => $upload->gold_reward,
                    'admin_notes' => $upload->admin_notes,
                    'created_at' => $upload->created_at->format('Y-m-d H:i:s'),
                    'approved_at' => $upload->approved_at?->format('Y-m-d H:i:s'),
                ];
            });

        return response()->json(['uploads' => $uploads]);
    }

    /**
     * Delete a pending upload
     */
    public function deleteUpload($id)
    {
        $user = Auth::user();

        $streamer = Streamer::where('user_id', $user->ID)->first();

        if (! $streamer) {
            return back()->withErrors(['message' => 'Streamer not found.']);
        }

        $upload = \App\Models\StreamerUpload::where('id', $id)
            ->where('streamer_id', $streamer->id)
            ->where('status', 'pending')
            ->first();

        if (! $upload) {
            return back()->withErrors(['message' => 'Upload not found or cannot be deleted.']);
        }

        $upload->deleteWithFile();

        return back()->with('success', 'Upload deleted successfully.');
    }

    /**
     * Get user characters from API or database cache
     */
    private function getUserCharacters(int $userId): array
    {
        try {
            $rolesData = $this->api->getRoles($userId);
            $roles = $rolesData['roles'] ?? [];

            $characters = [];
            foreach ($roles as $role) {
                try {
                    $base = $this->api->getRoleBase($role['id']);
                    $status = $this->api->getRoleStatus($role['id']);

                    $characters[] = [
                        'id' => $role['id'],
                        'name' => $role['name'],
                        'level' => ($status ?? [])['level'] ?? 0,
                        'class' => ($base ?? [])['cls'] ?? 0,
                    ];
                } catch (\Exception $e) {
                    $characters[] = [
                        'id' => $role['id'],
                        'name' => $role['name'],
                        'level' => 0,
                        'class' => 0,
                    ];
                }
            }

            return $characters;
        } catch (\Exception $e) {
            // Fallback to database cache
            return $this->getUserCharactersFromCache($userId);
        }
    }

    private function getStreamerCodeUsageCount(string $code): int
    {
        return (int) (
            DB::table('tripay_transactions')
                ->where('streamer_code', $code)
                ->where('status', 'paid')
                ->count()
            + DB::table('ipaymu_transactions')
                ->where('streamer_code', $code)
                ->where('status', 'success')
                ->count()
            + DB::table('duitku_transactions')
                ->where('streamer_code', $code)
                ->where('status', 'success')
                ->count()
            + DB::table('pakasir_transactions')
                ->where('streamer_code', $code)
                ->where('status', 'success')
                ->count()
        );
    }

    private function getStreamerCodeUsageHistory(string $code): array
    {
        $transactions = collect()
            ->merge($this->getStreamerGatewayTransactions('tripay_transactions', 'Tripay', 'reference', 'paid', $code))
            ->merge($this->getStreamerGatewayTransactions('ipaymu_transactions', 'Ipaymu', 'reference_id', 'success', $code))
            ->merge($this->getStreamerGatewayTransactions('duitku_transactions', 'Duitku', 'merchant_order_id', 'success', $code))
            ->merge($this->getStreamerGatewayTransactions('pakasir_transactions', 'Pakasir', 'reference_id', 'success', $code))
            ->sortByDesc('created_at')
            ->take(100)
            ->values();

        $characterIds = $transactions
            ->pluck('character_id')
            ->filter(fn ($characterId) => $characterId !== null && $characterId !== '')
            ->map(fn ($characterId) => (int) $characterId)
            ->unique()
            ->values();

        $characterNames = $characterIds->isEmpty()
            ? []
            : DB::table('player_rankings')
                ->whereIn('role_id', $characterIds)
                ->pluck('role_name', 'role_id')
                ->all();

        $characterClasses = $characterIds->isEmpty()
            ? []
            : DB::table('player_rankings')
                ->whereIn('role_id', $characterIds)
                ->pluck('cls', 'role_id')
                ->all();

        $userIds = $transactions
            ->pluck('user_id')
            ->filter()
            ->map(fn ($userId) => (int) $userId)
            ->unique()
            ->values();

        $userNames = $userIds->isEmpty()
            ? []
            : DB::table('users')
                ->whereIn('ID', $userIds)
                ->get(['ID', 'name', 'truename'])
                ->mapWithKeys(fn ($user) => [(int) $user->ID => $user->truename ?: $user->name ?: 'Unknown'])
                ->all();

        return $transactions
            ->map(function (array $transaction) use ($characterNames, $userNames) {
                $characterId = $transaction['character_id'] !== null && $transaction['character_id'] !== ''
                    ? (int) $transaction['character_id']
                    : null;
                $fallbackName = $userNames[(int) $transaction['user_id']] ?? null;

                return [
                    ...$transaction,
                    'character_id' => $characterId,
                    'character_name' => $characterId
                        ? ($characterNames[$characterId] ?? $this->resolveCharacterName($characterId, $fallbackName))
                        : ($fallbackName ?? 'Unknown'),
                    'character_class' => $characterId
                        ? ((int) ($characterClasses[$characterId] ?? 0))
                        : 0,
                ];
            })
            ->all();
    }

    private function getStreamerGatewayTransactions(
        string $table,
        string $gateway,
        string $referenceColumn,
        string $successStatus,
        string $code
    ) {
        return DB::table($table)
            ->where('streamer_code', $code)
            ->where('status', $successStatus)
            ->select([
                'id',
                'user_id',
                'character_id',
                'amount',
                'gold_amount',
                'payment_method',
                'paid_at',
                'created_at',
                DB::raw("'{$gateway}' as gateway"),
                DB::raw("{$referenceColumn} as reference"),
            ])
            ->get()
            ->map(fn ($transaction) => [
                'id' => strtolower($gateway).'-'.$transaction->id,
                'gateway' => $transaction->gateway,
                'reference' => $transaction->reference,
                'user_id' => (int) $transaction->user_id,
                'character_id' => $transaction->character_id,
                'amount' => (int) $transaction->amount,
                'gold_amount' => (int) $transaction->gold_amount,
                'payment_method' => $transaction->payment_method,
                'paid_at' => $transaction->paid_at,
                'created_at' => $transaction->created_at,
            ]);
    }

    private function resolveCharacterName(int $characterId, ?string $fallbackName = null): string
    {
        try {
            $roleBase = $this->api->getRoleBase($characterId);
            if (isset($roleBase['name']) && $roleBase['name'] !== '') {
                return $roleBase['name'];
            }
        } catch (\Exception $e) {
            return $fallbackName ?? 'Character #'.$characterId;
        }

        return $fallbackName ?? 'Character #'.$characterId;
    }

    /**
     * Get user characters from database cache (player_rankings)
     */
    private function getUserCharactersFromCache(int $userId): array
    {
        $rankings = DB::table('player_rankings')
            ->where('user_id', $userId)
            ->orderBy('level', 'DESC')
            ->get();

        $characters = [];
        foreach ($rankings as $ranking) {
            $characters[] = [
                'id' => $ranking->role_id,
                'name' => $ranking->role_name,
                'level' => $ranking->level,
                'class' => $ranking->cls,
            ];
        }

        return $characters;
    }

    /**
     * Send Discord notification for streamer upload
     */
    private function sendDiscordNotification(Streamer $streamer, \App\Models\StreamerUpload $upload): void
    {
        try {
            $webhookUrl = DB::table('settings')
                ->where('key', 'streamer_discord_webhook_url')
                ->first()?->value;

            if (empty($webhookUrl)) {
                return;
            }

            $imageUrl = asset('storage/'.$upload->image_path);

            $embed = [
                'title' => 'Streamer Notification',
                'description' => "<@{$streamer->discord_id}> posted result live",
                'color' => 0x7C3AED, // Purple
                'image' => [
                    'url' => $imageUrl,
                ],
                'footer' => [
                    'text' => 'Perfect World '.config('app.name').' • '.now()->format('n/j/Y - g:i A'),
                ],
            ];

            $payload = [
                'embeds' => [$embed],
            ];

            // Add wait=true to get message object in response
            $response = \Illuminate\Support\Facades\Http::post($webhookUrl.'?wait=true', $payload);

            if ($response->successful()) {
                $messageId = $response->json('id');
                if ($messageId) {
                    $upload->update(['discord_message_id' => $messageId]);
                }
            }
        } catch (\Exception $e) {
            \Log::warning('Failed to send Discord notification for streamer upload', [
                'streamer_id' => $streamer->id,
                'upload_id' => $upload->id,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
