<?php

/**
 * 文件功能：前台邮箱找回密码控制器
 *
 * 提供独立的找回密码页、发送邮箱重置链接、展示重置页以及提交新密码功能。
 */

namespace App\Http\Controllers;

use App\Http\Requests\ResetPasswordRequest;
use App\Http\Requests\SendPasswordResetLinkRequest;
use App\Models\Sysparam;
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;

/**
 * 类功能：处理首页邮箱找回密码的完整流程。
 */
class PasswordResetController extends Controller
{
    /**
     * 展示独立的邮箱找回密码页面。
     */
    public function create(): View
    {
        return view('password-forgot', [
            'systemName' => Sysparam::where('alias', 'sys_name')->value('body') ?? '和平聊吧',
            'smtpEnabled' => $this->isPasswordResetMailEnabled(),
        ]);
    }

    /**
     * 发送邮箱找回密码链接。
     */
    public function storeLink(SendPasswordResetLinkRequest $request): JsonResponse
    {
        if (! $this->isPasswordResetMailEnabled()) {
            return response()->json([
                'status' => 'error',
                'message' => '系统暂未开启邮箱发信服务，当前无法通过邮箱找回密码。',
            ], 403);
        }

        $email = trim((string) $request->string('email'));

        // 邮箱找回必须保证一邮一号，否则重置目标会产生歧义。
        if (User::query()->where('email', $email)->count() > 1) {
            return response()->json([
                'status' => 'error',
                'message' => '该邮箱绑定了多个账号，暂不支持自助找回，请联系管理员处理。',
            ], 422);
        }

        $status = Password::sendResetLink(['email' => $email]);

        if ($status === Password::RESET_LINK_SENT) {
            return response()->json([
                'status' => 'success',
                'message' => '如果该邮箱已绑定账号，系统已发送重置邮件。链接 60 分钟内有效，请注意查收。',
            ]);
        }

        if ($status === Password::RESET_THROTTLED) {
            return response()->json([
                'status' => 'error',
                'message' => '发送过于频繁，请稍后再试。',
            ], 429);
        }

        if ($status === Password::INVALID_USER) {
            return response()->json([
                'status' => 'success',
                'message' => '如果该邮箱已绑定账号，系统已发送重置邮件。请检查收件箱与垃圾邮件箱。',
            ]);
        }

        return response()->json([
            'status' => 'error',
            'message' => '找回密码邮件发送失败，请稍后重试。',
        ], 500);
    }

    /**
     * 展示独立的重置密码页面。
     */
    public function edit(Request $request, string $token): View
    {
        return view('password-reset', [
            'systemName' => Sysparam::where('alias', 'sys_name')->value('body') ?? '和平聊吧',
            'token' => $token,
            'email' => (string) $request->query('email', ''),
        ]);
    }

    /**
     * 提交新的登录密码并完成重置。
     */
    public function update(ResetPasswordRequest $request): RedirectResponse
    {
        $credentials = $request->validated();

        $status = Password::reset(
            $credentials,
            function (User $user, #[\SensitiveParameter] string $password): void {
                // 重置成功后同步刷新 remember_token，避免旧设备继续沿用旧令牌。
                $user->forceFill([
                    'password' => Hash::make($password),
                    'remember_token' => Str::random(60),
                ])->save();

                event(new PasswordReset($user));
            }
        );

        if ($status === Password::PASSWORD_RESET) {
            return redirect()->route('home')->with('status', '密码已重置成功，请使用原昵称和新密码重新登录。');
        }

        return back()
            ->withInput($request->except('password', 'password_confirmation'))
            ->withErrors([
                'email' => $this->resolveResetFailureMessage($status),
            ]);
    }

    /**
     * 判断系统是否已开启邮箱发信服务。
     */
    private function isPasswordResetMailEnabled(): bool
    {
        return Sysparam::where('alias', 'smtp_enabled')->value('body') === '1';
    }

    /**
     * 将 Laravel 密码重置状态码转换为中文错误提示。
     */
    private function resolveResetFailureMessage(string $status): string
    {
        return match ($status) {
            Password::INVALID_TOKEN => '重置链接无效或已过期，请重新申请邮箱找回。',
            Password::INVALID_USER => '该邮箱未绑定可重置的账号，请确认后再试。',
            default => '密码重置失败，请重新获取重置链接后再试。',
        };
    }
}
