<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Carbon\Carbon;

class PasswordResetController extends Controller
{
    /**
     * Show password reset request form
     */
    public function showResetRequestForm()
    {
        return view('auth.password-reset-request');
    }

    /**
     * Send password reset email
     */
    public function sendResetEmail(Request $request)
    {
        $request->validate([
            'email' => 'required|email'
        ], [
            'email.required' => 'La mail è obbligatoria',
            'email.email' => 'Inserisci un indirizzo email valido'
        ]);

        $this->logSecurityEvent('reset_requested', $request->email);

        try {
            $user = $this->findUserInMasterDatabase($request->email);

            if (!$user) {
                $this->logSecurityEvent('reset_requested_invalid_email', $request->email);
                return back()->with('success', 'Se l\'email esiste nel sistema, riceverai le istruzioni per il reset della password.');
            }

            if ($this->hasRecentResetRequest($request->email)) {
                $this->logSecurityEvent('reset_requested_too_soon', $request->email);
                return back()->with('error', 'È già stata inviata una richiesta di reset per questa email. Controlla la tua casella di posta o riprova più tardi.');
            }

            $token = Str::random(64);

            $this->storeResetToken($request->email, $token);

            $this->sendPasswordResetEmail($request->email, $token, $user);

            $this->logSecurityEvent('reset_email_sent', $request->email);

            return back()->with('success', 'Se l\'email esiste nel sistema, riceverai le istruzioni per il reset della password.');
        } catch (\Exception $e) {
            $this->logSecurityEvent('reset_request_failed', $request->email, ['error' => $e->getMessage()]);
            return back()->with('error', 'Errore durante l\'invio dell\'email. Riprova più tardi.');
        }
    }

    /**
     * Show password reset form
     */
    public function showResetForm($token)
    {
        return view('auth.password-reset-form', ['token' => $token]);
    }

    /**
     * Reset password
     */
    public function resetPassword(Request $request)
    {
        $request->validate([
            'token' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:6|confirmed'
        ], [
            'email.required' => 'La mail è obbligatoria',
            'email.email' => 'Inserisci un indirizzo email valido',
            'password.required' => 'La password è obbligatoria',
            'password.min' => 'La password deve essere di almeno 6 caratteri',
            'password.confirmed' => 'Le password non coincidono'
        ]);

        try {
            // Verify reset token
            $resetRecord = $this->verifyResetToken($request->email, $request->token);

            if (!$resetRecord) {
                return back()->with('error', 'Token non valido o scaduto.');
            }

            // Get user from master database
            $user = $this->findUserInMasterDatabase($request->email);

            if (!$user) {
                return back()->with('error', 'Utente non trovato.');
            }

            // Update password in both databases
            $this->updatePasswordInBothDatabases($request->email, $request->password, $user);

            // Delete reset token
            $this->deleteResetToken($request->email);

            // Send password change notification
            $this->sendPasswordChangeNotification($request->email, $user->name);

            Log::info('Password reset completed with notification', [
                'email' => $request->email
            ]);

            return redirect('/')->with('success', 'Password aggiornata con successo. Ti abbiamo inviato una email di conferma.');
        } catch (\Exception $e) {
            Log::error('Password reset failed', [
                'email' => $request->email,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Errore durante il reset della password. Riprova più tardi.');
        }
    }

    /**
     * Find user in master database
     */
    private function findUserInMasterDatabase($email)
    {
        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_reset' => $masterConfig]);

            $user = DB::connection('master_reset')
                ->table('users')
                ->where('email', $email)
                ->first();

            DB::purge('master_reset');

            return $user;
        } catch (\Exception $e) {
            Log::error('Failed to find user in master database', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * Store reset token in master database
     */
    private function storeResetToken($email, $token)
    {
        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_reset_token' => $masterConfig]);

            DB::connection('master_reset_token')
                ->table('password_resets')
                ->where('email', $email)
                ->delete();

            DB::connection('master_reset_token')
                ->table('password_resets')
                ->insert([
                    'email' => $email,
                    'token' => Hash::make($token),
                    'created_at' => Carbon::now()
                ]);

            DB::purge('master_reset_token');
        } catch (\Exception $e) {
            Log::error('Failed to store reset token', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }

    /**
     * Verify reset token
     */
    private function verifyResetToken($email, $token)
    {
        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_verify' => $masterConfig]);

            $resetRecord = DB::connection('master_verify')
                ->table('password_resets')
                ->where('email', $email)
                ->first();

            DB::purge('master_verify');

            if (!$resetRecord) {
                return null;
            }

            $isValidToken = Hash::check($token, $resetRecord->token);
            $isNotExpired = Carbon::parse($resetRecord->created_at)->addHours(24)->isFuture();

            if ($isValidToken && $isNotExpired) {
                return $resetRecord;
            }

            return null;
        } catch (\Exception $e) {
            Log::error('Failed to verify reset token', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * Update password in both master and tenant databases
     */
    private function updatePasswordInBothDatabases($email, $newPassword, $masterUser)
    {
        $hashedPassword = Hash::make($newPassword);

        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_update' => $masterConfig]);

            DB::connection('master_update')
                ->table('users')
                ->where('email', $email)
                ->update(['password' => $hashedPassword]);

            DB::purge('master_update');

            Log::info('Password updated in master database', ['email' => $email]);

            if ($masterUser->tenant_database) {
                $tenantConfig = [
                    'driver' => 'mysql',
                    'host' => env('DB_HOST', '127.0.0.1'),
                    'port' => env('DB_PORT', '3306'),
                    'database' => $masterUser->tenant_database,
                    'username' => $masterUser->tenant_username,
                    'password' => $masterUser->tenant_password,
                    'charset' => 'utf8mb4',
                    'collation' => 'utf8mb4_unicode_ci',
                    'prefix' => '',
                    'strict' => true,
                    'engine' => null,
                ];

                config(['database.connections.tenant_update' => $tenantConfig]);

                DB::connection('tenant_update')
                    ->table('users')
                    ->where('email', $email)
                    ->update(['password' => $hashedPassword]);

                DB::purge('tenant_update');

                Log::info('Password updated in tenant database', [
                    'email' => $email,
                    'tenant_database' => $masterUser->tenant_database
                ]);
            }
        } catch (\Exception $e) {
            Log::error('Failed to update password in databases', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }

    /**
     * Delete reset token
     */
    private function deleteResetToken($email)
    {
        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_delete_token' => $masterConfig]);

            DB::connection('master_delete_token')
                ->table('password_resets')
                ->where('email', $email)
                ->delete();

            DB::purge('master_delete_token');
        } catch (\Exception $e) {
            Log::error('Failed to delete reset token', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
        }
    }

    private function sendPasswordChangeNotification($email, $name)
    {
        try {
            $emailData = [
                'name' => $name,
                'email' => $email,
                'change_time' => now()->format('d/m/Y H:i'),
                'ip_address' => request()->ip()
            ];

            Mail::send('emails.password-changed', $emailData, function ($message) use ($email, $name) {
                $message->to($email, $name)
                    ->subject('La tua password è stata modificata')
                    ->from(config('mail.from.address'), config('mail.from.name'));
            });

            Log::info('Password change notification sent', [
                'email' => $email,
                'name' => $name
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to send password change notification', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            return false;
        }
    }


    /**
     * Send password reset email
     */
    private function sendPasswordResetEmail($email, $token, $user)
    {
        try {
            $resetUrl = url('/password-reset/' . $token . '?email=' . urlencode($email));
            $companyName = 'Leezard';

            $emailData = [
                'name' => $user->name,
                'email' => $email,
                'reset_url' => $resetUrl,
                'company' => $companyName,
                'expires_at' => Carbon::now()->addHours(24)->format('d/m/Y H:i')
            ];

            Mail::send('emails.password-reset', $emailData, function ($message) use ($email, $companyName, $user) {
                $message->to($email, $user->name)
                    ->subject('Reset Password -  Leezard')
                    ->from(config('mail.from.address'), config('mail.from.name'));
            });

            Log::info('Password reset email sent', ['email' => $email]);
        } catch (\Exception $e) {
            Log::error('Failed to send password reset email', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }

    private function logSecurityEvent($event, $email, $additionalData = [])
    {
        Log::info('Password Reset Security Event', array_merge([
            'event' => $event,
            'email' => $email,
            'ip' => request()->ip(),
            'user_agent' => request()->userAgent(),
            'timestamp' => now()
        ], $additionalData));
    }

    private function hasRecentResetRequest($email)
    {
        try {
            $masterConfig = [
                'driver' => 'mysql',
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE'),
                'username' => env('DB_USERNAME'),
                'password' => env('DB_PASSWORD'),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'strict' => true,
                'engine' => null,
            ];

            config(['database.connections.master_check_recent' => $masterConfig]);

            $recentRequest = DB::connection('master_check_recent')
                ->table('password_resets')
                ->where('email', $email)
                ->where('created_at', '>', Carbon::now()->subMinutes(5)) // 5 minutes cooldown
                ->first();

            DB::purge('master_check_recent');

            return $recentRequest !== null;
        } catch (\Exception $e) {
            Log::error('Failed to check recent reset requests', [
                'email' => $email,
                'error' => $e->getMessage()
            ]);
            return false;
        }
    }
}
