<?php

namespace App\Http\Controllers\Admin\Settings;

use App\Http\Controllers\Controller;
use App\Models\DiscordWebhookSettings;
use App\Models\ExpRateSchedule;
use App\Services\Api\API;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;

class ServerRatesController extends Controller
{
    protected API $api;

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

    public function index()
    {
        // Check if server is online
        $serverOnline = $this->api->serverOnline();

        // If server is offline, reset all settings to default values
        if (! $serverOnline) {
            $defaultSettings = [
                'exp_rate' => 1,
                'double_money' => 0,
                'double_drop' => 0,
                'double_sp' => 0,
                'no_trade' => 0,
                'no_auction' => 0,
                'no_mail' => 0,
                'updated_at' => now(),
            ];

            // Update or create default settings in database
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                array_merge($defaultSettings, ['created_at' => now()])
            );

            // Return default settings for frontend
            $settings = (object) [
                'exp_rate' => 1,
                'double_money' => false,
                'double_drop' => false,
                'double_sp' => false,
                'no_trade' => false,
                'no_auction' => false,
                'no_mail' => false,
            ];

            $schedules = ExpRateSchedule::orderBy('start_time', 'desc')->get();

            return Inertia::render('admin/settings/exprate/index', [
                'settings' => $settings,
                'serverOnline' => $serverOnline,
                'schedules' => $schedules,
            ]);
        }

        // Server is online, get settings from database
        $settings = DB::table('server_rates')->first();

        if (! $settings) {
            // Default settings when database is empty
            $settings = (object) [
                'exp_rate' => 1,
                'double_money' => false,
                'double_drop' => false,
                'double_sp' => false,
                'no_trade' => false,
                'no_auction' => false,
                'no_mail' => false,
            ];
        } else {
            // Convert 0/1 to boolean for frontend
            $settings->double_money = (bool) $settings->double_money;
            $settings->double_drop = (bool) $settings->double_drop;
            $settings->double_sp = (bool) $settings->double_sp;
            $settings->no_trade = (bool) $settings->no_trade;
            $settings->no_auction = (bool) $settings->no_auction;
            $settings->no_mail = (bool) $settings->no_mail;
        }

        $schedules = ExpRateSchedule::orderBy('start_time', 'desc')->get();

        // Get Discord webhook settings
        $discordSettings = \App\Models\DiscordWebhookSettings::first();

        return Inertia::render('admin/settings/exprate/index', [
            'settings' => $settings,
            'serverOnline' => $serverOnline,
            'schedules' => $schedules,
            'discordSettings' => $discordSettings,
        ]);
    }

    public function updateExpRate(Request $request)
    {
        $request->validate([
            'exp_rate' => 'required|integer|min:1|max:100',
        ]);

        $result = $this->api->setExpRate($request->exp_rate);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'exp_rate' => $request->exp_rate,
                    'updated_at' => now(),
                ]
            );

            return back()->with('success', 'Exp rate updated to x'.$request->exp_rate.' successfully.');
        }

        return back()->with('error', 'Failed to update exp rate.');
    }

    public function updateDoubleMoney(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating double money rate', ['enabled' => $request->enabled]);

        $result = $this->api->setMoneyRate($request->enabled);

        \Log::info('API Response for double money', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'double_money' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('Double money saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Double money '.($request->enabled ? 'enabled' : 'disabled').' successfully.');
        }

        \Log::error('Failed to update double money rate', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update double money rate.');
    }

    public function updateDoubleDrop(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating double drop rate', ['enabled' => $request->enabled]);

        $result = $this->api->setDropRate($request->enabled);

        \Log::info('API Response for double drop', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'double_drop' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('Double drop saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Double drop '.($request->enabled ? 'enabled' : 'disabled').' successfully.');
        }

        \Log::error('Failed to update double drop rate', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update double drop rate.');
    }

    public function updateDoubleSp(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating double SP rate', ['enabled' => $request->enabled]);

        $result = $this->api->setSpRate($request->enabled);

        \Log::info('API Response for double SP', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'double_sp' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('Double SP saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Double SP '.($request->enabled ? 'enabled' : 'disabled').' successfully.');
        }

        \Log::error('Failed to update double SP rate', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update double SP rate.');
    }

    public function updateNoTrade(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating no trade', ['enabled' => $request->enabled]);

        $result = $this->api->setNoTrade($request->enabled);

        \Log::info('API Response for no trade', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'no_trade' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('No trade saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Trade '.($request->enabled ? 'disabled' : 'enabled').' successfully.');
        }

        \Log::error('Failed to update no trade', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update trade setting.');
    }

    public function updateNoAuction(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating no auction', ['enabled' => $request->enabled]);

        $result = $this->api->setNoAuction($request->enabled);

        \Log::info('API Response for no auction', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'no_auction' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('No auction saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Auction '.($request->enabled ? 'disabled' : 'enabled').' successfully.');
        }

        \Log::error('Failed to update no auction', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update auction setting.');
    }

    public function updateNoMail(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
        ]);

        \Log::info('Updating no mail', ['enabled' => $request->enabled]);

        $result = $this->api->setNoMail($request->enabled);

        \Log::info('API Response for no mail', ['result' => $result]);

        if ($result['success']) {
            DB::table('server_rates')->updateOrInsert(
                ['id' => 1],
                [
                    'no_mail' => $request->enabled ? 1 : 0,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );

            \Log::info('No mail saved to database', ['value' => $request->enabled ? 1 : 0]);

            return redirect()->back()->with('success', 'Mail '.($request->enabled ? 'disabled' : 'enabled').' successfully.');
        }

        \Log::error('Failed to update no mail', ['result' => $result]);

        return redirect()->back()->with('error', 'Failed to update mail setting.');
    }

    public function getSchedules()
    {
        $schedules = ExpRateSchedule::orderBy('start_time', 'desc')->get();

        return response()->json($schedules);
    }

    public function storeSchedule(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'type' => 'required|in:exp_rate,double_money,double_drop,double_sp,no_trade,no_auction,no_mail',
            'start_time' => 'required|date|after:now',
            'end_time' => 'required|date|after:start_time',
            'exp_rate_value' => 'nullable|integer|min:1|max:100',
            'double_money_value' => 'nullable|boolean',
            'double_drop_value' => 'nullable|boolean',
            'double_sp_value' => 'nullable|boolean',
            'no_trade_value' => 'nullable|boolean',
            'no_auction_value' => 'nullable|boolean',
            'no_mail_value' => 'nullable|boolean',
            'broadcast_enabled' => 'nullable|boolean',
            'broadcast_message' => 'nullable|string|max:500',
            'end_broadcast_enabled' => 'nullable|boolean',
            'end_broadcast_message' => 'nullable|string|max:500',
        ]);

        $schedule = ExpRateSchedule::create([
            'name' => $request->name,
            'type' => $request->type,
            'start_time' => $request->start_time,
            'end_time' => $request->end_time,
            'exp_rate_value' => $request->exp_rate_value ?? 1,
            'double_money_value' => $request->double_money_value ?? false,
            'double_drop_value' => $request->double_drop_value ?? false,
            'double_sp_value' => $request->double_sp_value ?? false,
            'no_trade_value' => $request->no_trade_value ?? false,
            'no_auction_value' => $request->no_auction_value ?? false,
            'no_mail_value' => $request->no_mail_value ?? false,
            'broadcast_enabled' => $request->broadcast_enabled ?? false,
            'broadcast_message' => $request->broadcast_message ?? null,
            'end_broadcast_enabled' => $request->end_broadcast_enabled ?? false,
            'end_broadcast_message' => $request->end_broadcast_message ?? null,
            'is_active' => true,
            'is_applied' => false,
        ]);

        return back()->with('success', 'Schedule created successfully.');
    }

    public function updateSchedule(Request $request, $id)
    {
        $schedule = ExpRateSchedule::findOrFail($id);

        $request->validate([
            'name' => 'required|string|max:255',
            'type' => 'required|in:exp_rate,double_money,double_drop,double_sp,no_trade,no_auction,no_mail',
            'start_time' => 'required|date',
            'end_time' => 'required|date|after:start_time',
            'exp_rate_value' => 'nullable|integer|min:1|max:100',
            'double_money_value' => 'nullable|boolean',
            'double_drop_value' => 'nullable|boolean',
            'double_sp_value' => 'nullable|boolean',
            'no_trade_value' => 'nullable|boolean',
            'no_auction_value' => 'nullable|boolean',
            'no_mail_value' => 'nullable|boolean',
            'broadcast_enabled' => 'nullable|boolean',
            'broadcast_message' => 'nullable|string|max:500',
            'end_broadcast_enabled' => 'nullable|boolean',
            'end_broadcast_message' => 'nullable|string|max:500',
        ]);

        $schedule->update([
            'name' => $request->name,
            'type' => $request->type,
            'start_time' => $request->start_time,
            'end_time' => $request->end_time,
            'exp_rate_value' => $request->exp_rate_value ?? 1,
            'double_money_value' => $request->double_money_value ?? false,
            'double_drop_value' => $request->double_drop_value ?? false,
            'double_sp_value' => $request->double_sp_value ?? false,
            'no_trade_value' => $request->no_trade_value ?? false,
            'no_auction_value' => $request->no_auction_value ?? false,
            'no_mail_value' => $request->no_mail_value ?? false,
            'broadcast_enabled' => $request->broadcast_enabled ?? false,
            'broadcast_message' => $request->broadcast_message ?? null,
            'end_broadcast_enabled' => $request->end_broadcast_enabled ?? false,
            'end_broadcast_message' => $request->end_broadcast_message ?? null,
        ]);

        return back()->with('success', 'Schedule updated successfully.');
    }

    public function destroySchedule($id)
    {
        $schedule = ExpRateSchedule::findOrFail($id);

        if ($schedule->is_applied) {
            return back()->with('error', 'Cannot delete an applied schedule.');
        }

        $schedule->delete();

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

    public function toggleSchedule($id)
    {
        $schedule = ExpRateSchedule::findOrFail($id);
        $schedule->is_active = ! $schedule->is_active;
        $schedule->save();

        return back()->with('success', 'Schedule status updated successfully.');
    }

    public function applySchedule($id)
    {
        $schedule = ExpRateSchedule::findOrFail($id);
        $serverOnline = $this->api->serverOnline();

        if (! $serverOnline) {
            return back()->with('error', 'Server is offline. Cannot apply schedule.');
        }

        if ($schedule->is_applied) {
            return back()->with('error', 'Schedule already applied.');
        }

        $currentSettings = DB::table('server_rates')->first();

        $originalValues = json_encode([
            'exp_rate' => $currentSettings->exp_rate ?? 1,
            'double_money' => $currentSettings->double_money ?? 0,
            'double_drop' => $currentSettings->double_drop ?? 0,
            'double_sp' => $currentSettings->double_sp ?? 0,
            'no_trade' => $currentSettings->no_trade ?? 0,
            'no_auction' => $currentSettings->no_auction ?? 0,
            'no_mail' => $currentSettings->no_mail ?? 0,
        ]);

        $success = true;
        $errorMessage = '';

        try {
            switch ($schedule->type) {
                case 'exp_rate':
                    $result = $this->api->setExpRate($schedule->exp_rate_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update exp rate.';
                    }
                    break;
                case 'double_money':
                    $result = $this->api->setMoneyRate($schedule->double_money_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update double money rate.';
                    }
                    break;
                case 'double_drop':
                    $result = $this->api->setDropRate($schedule->double_drop_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update double drop rate.';
                    }
                    break;
                case 'double_sp':
                    $result = $this->api->setSpRate($schedule->double_sp_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update double SP rate.';
                    }
                    break;
                case 'no_trade':
                    $result = $this->api->setNoTrade($schedule->no_trade_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update trade setting.';
                    }
                    break;
                case 'no_auction':
                    $result = $this->api->setNoAuction($schedule->no_auction_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update auction setting.';
                    }
                    break;
                case 'no_mail':
                    $result = $this->api->setNoMail($schedule->no_mail_value);
                    if (! $result['success']) {
                        $success = false;
                        $errorMessage = 'Failed to update mail setting.';
                    }
                    break;
            }

            if ($success) {
                DB::table('server_rates')->updateOrInsert(
                    ['id' => 1],
                    [
                        'exp_rate' => $schedule->type === 'exp_rate' ? $schedule->exp_rate_value : ($currentSettings->exp_rate ?? 1),
                        'double_money' => $schedule->type === 'double_money' ? ($schedule->double_money_value ? 1 : 0) : ($currentSettings->double_money ?? 0),
                        'double_drop' => $schedule->type === 'double_drop' ? ($schedule->double_drop_value ? 1 : 0) : ($currentSettings->double_drop ?? 0),
                        'double_sp' => $schedule->type === 'double_sp' ? ($schedule->double_sp_value ? 1 : 0) : ($currentSettings->double_sp ?? 0),
                        'no_trade' => $schedule->type === 'no_trade' ? ($schedule->no_trade_value ? 1 : 0) : ($currentSettings->no_trade ?? 0),
                        'no_auction' => $schedule->type === 'no_auction' ? ($schedule->no_auction_value ? 1 : 0) : ($currentSettings->no_auction ?? 0),
                        'no_mail' => $schedule->type === 'no_mail' ? ($schedule->no_mail_value ? 1 : 0) : ($currentSettings->no_mail ?? 0),
                        'updated_at' => now(),
                    ]
                );

                $schedule->update([
                    'is_applied' => true,
                    'original_value' => $originalValues,
                ]);

                return back()->with('success', 'Schedule applied successfully.');
            } else {
                return back()->with('error', $errorMessage);
            }
        } catch (\Exception $e) {
            Log::error('Error applying schedule', ['error' => $e->getMessage()]);

            return back()->with('error', 'An error occurred while applying the schedule.');
        }
    }

    public function revertSchedule($id)
    {
        $schedule = ExpRateSchedule::findOrFail($id);
        $serverOnline = $this->api->serverOnline();

        if (! $serverOnline) {
            return back()->with('error', 'Server is offline. Cannot revert schedule.');
        }

        if (! $schedule->is_applied || ! $schedule->original_value) {
            return back()->with('error', 'Cannot revert this schedule.');
        }

        try {
            $originalValues = json_decode($schedule->original_value, true);

            $success = true;
            $errorMessage = '';

            if ($schedule->type === 'exp_rate') {
                $result = $this->api->setExpRate($originalValues['exp_rate']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert exp rate.';
                }
            } elseif ($schedule->type === 'double_money') {
                $result = $this->api->setMoneyRate($originalValues['double_money']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert double money rate.';
                }
            } elseif ($schedule->type === 'double_drop') {
                $result = $this->api->setDropRate($originalValues['double_drop']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert double drop rate.';
                }
            } elseif ($schedule->type === 'double_sp') {
                $result = $this->api->setSpRate($originalValues['double_sp']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert double SP rate.';
                }
            } elseif ($schedule->type === 'no_trade') {
                $result = $this->api->setNoTrade($originalValues['no_trade']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert trade setting.';
                }
            } elseif ($schedule->type === 'no_auction') {
                $result = $this->api->setNoAuction($originalValues['no_auction']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert auction setting.';
                }
            } elseif ($schedule->type === 'no_mail') {
                $result = $this->api->setNoMail($originalValues['no_mail']);
                if (! $result['success']) {
                    $success = false;
                    $errorMessage = 'Failed to revert mail setting.';
                }
            }

            if ($success) {
                DB::table('server_rates')->updateOrInsert(
                    ['id' => 1],
                    [
                        'exp_rate' => $originalValues['exp_rate'],
                        'double_money' => $originalValues['double_money'],
                        'double_drop' => $originalValues['double_drop'],
                        'double_sp' => $originalValues['double_sp'],
                        'no_trade' => $originalValues['no_trade'],
                        'no_auction' => $originalValues['no_auction'],
                        'no_mail' => $originalValues['no_mail'],
                        'updated_at' => now(),
                    ]
                );

                $schedule->update(['is_applied' => false]);

                return back()->with('success', 'Schedule reverted successfully.');
            } else {
                return back()->with('error', $errorMessage);
            }
        } catch (\Exception $e) {
            Log::error('Error reverting schedule', ['error' => $e->getMessage()]);

            return back()->with('error', 'An error occurred while reverting the schedule.');
        }
    }

    public function updateDiscordWebhook(Request $request)
    {
        $request->validate([
            'enabled' => 'required|boolean',
            'webhook_url' => 'nullable|string|max:500',
            'bot_username' => 'nullable|string|max:100',
            'avatar_url' => 'nullable|string|max:500',
        ]);

        $discordSettings = DiscordWebhookSettings::first();

        if (! $discordSettings) {
            $discordSettings = new DiscordWebhookSettings;
        }

        $discordSettings->enabled = $request->enabled;
        $discordSettings->webhook_url = $request->webhook_url ?? '';
        $discordSettings->bot_username = $request->bot_username ?? null;
        $discordSettings->avatar_url = $request->avatar_url ?? null;
        $discordSettings->save();

        return back()->with('success', 'Discord webhook settings updated successfully.');
    }

    public function testDiscordWebhook()
    {
        $discordSettings = DiscordWebhookSettings::first();

        if (! $discordSettings || ! $discordSettings->enabled || ! $discordSettings->webhook_url) {
            return back()->with('error', 'Discord webhook is not configured or enabled.');
        }

        $result = $this->api->sendDiscordWebhook(
            'Test Webhook Message - This is a test message from server. Discord webhook is working correctly!',
            $discordSettings->webhook_url,
            $discordSettings->bot_username,
            $discordSettings->avatar_url
        );

        if ($result['success']) {
            return back()->with('success', 'Test webhook sent successfully to Discord!');
        } else {
            return back()->with('error', 'Failed to send test webhook: '.$result['message']);
        }
    }
}
