import { useEffect, useState, type FormEvent } from "react"
import { Link } from "react-router-dom"
import { Card, Button, TextField, Label, Input } from "@heroui/react"
import { useAuth } from "../contexts/AuthContext"
import { sendLoginCode, sendLoginSmsCode } from "../api/auth"
import { getOAuthProviders, getOAuthUrl, type OAuthProvider } from "../api/oauth"
import { SkeletonBlock, type SkeletonSpec } from "../utils/skeleton"
import { toast } from "../utils/toast"
import { verifyCaptcha } from "../utils/geetest"
import BrandLogo from "../components/BrandLogo"

type Mode = "password" | "email" | "sms"

const formSkeleton: SkeletonSpec[] = [
  { type: "stack", gap: 16, children: [
    { type: "stack", gap: 8, children: [
      { type: "rect", w: 64, h: 12 },
      { type: "rect", h: 40, rounded: 12 },
    ]},
    { type: "stack", gap: 8, children: [
      { type: "rect", w: 64, h: 12 },
      { type: "rect", h: 40, rounded: 12 },
    ]},
    { type: "rect", h: 44, rounded: 12 },
  ]},
]

const CN_PHONE = /^1[3-9]\d{9}$/

const MODES: { key: Mode; label: string }[] = [
  { key: "password", label: "密码登录" },
  { key: "email", label: "邮箱验证码" },
  { key: "sms", label: "短信验证码" },
]

export default function Login() {
  const { login, loginByCode, loginBySms, isLoading: authLoading } = useAuth()
  const [mode, setMode] = useState<Mode>("password")
  const [identifier, setIdentifier] = useState("")
  const [email, setEmail] = useState("")
  const [phone, setPhone] = useState("")
  const [password, setPassword] = useState("")
  const [code, setCode] = useState("")
  const [isLoading, setIsLoading] = useState(false)
  const [mounting, setMounting] = useState(true)
  const [cooldown, setCooldown] = useState(0)
  const [sendingCode, setSendingCode] = useState(false)
  const [oauthProviders, setOAuthProviders] = useState<OAuthProvider[]>([])
  const [oauthLoading, setOAuthLoading] = useState(false)

  useEffect(() => {
    getOAuthProviders().then(setOAuthProviders)
  }, [])

  useEffect(() => {
    const t = setTimeout(() => setMounting(false), 350)
    return () => clearTimeout(t)
  }, [])

  useEffect(() => {
    if (cooldown <= 0) return
    const t = setInterval(() => setCooldown((c) => (c <= 1 ? 0 : c - 1)), 1000)
    return () => clearInterval(t)
  }, [cooldown])

  useEffect(() => {
    setCode("")
    setCooldown(0)
  }, [mode])

  const showSkeleton = authLoading || mounting
  const modeIndex = MODES.findIndex((m) => m.key === mode)

  const handleSendCode = async () => {
    if (cooldown > 0 || sendingCode) return
    if (mode === "email") {
      if (!email) {
        toast.error("请先填写邮箱")
        return
      }
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
        toast.error("邮箱格式不正确")
        return
      }
    } else if (mode === "sms") {
      if (!phone) {
        toast.error("请先填写手机号")
        return
      }
      if (!CN_PHONE.test(phone)) {
        toast.error("手机号格式不正确")
        return
      }
    }
    setSendingCode(true)
    try {
      const captcha = await verifyCaptcha()
      const res = mode === "email"
        ? await sendLoginCode(email, captcha)
        : await sendLoginSmsCode(phone, captcha)
      setCooldown(res.data?.cooldown ?? 60)
      toast.success(mode === "email" ? "验证码已发送，请检查邮箱" : "验证码已发送，请查收短信")
    } catch (err: unknown) {
      const detail = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail
      toast.error(detail || (err instanceof Error ? err.message : "发送失败"))
    } finally {
      setSendingCode(false)
    }
  }

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault()
    setIsLoading(true)
    try {
      const captcha = await verifyCaptcha()
      if (mode === "password") {
        await login(identifier, password, captcha)
      } else if (mode === "email") {
        await loginByCode(email, code, captcha)
      } else {
        await loginBySms(phone, code, captcha)
      }
      toast.success("登录成功")
    } catch (err: unknown) {
      const detail = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail
      const message = detail || (err instanceof Error ? err.message : "登录失败")
      toast.error(message)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div className="qycw-page-enter flex flex-col gap-6">
      {/* Mobile logo (hidden on lg) */}
      <div className="flex lg:hidden mb-2">
        <BrandLogo className="h-24 object-contain" />
      </div>

      <div>
        {showSkeleton ? (
          <SkeletonBlock spec={[
            { type: "rect", w: 128, h: 24 },
            { type: "rect", w: 200, h: 12 },
          ]} />
        ) : (
          <div className="qycw-content-fade">
            <h2 className="text-xl font-bold text-gray-800">欢迎回来</h2>
            <p className="mt-1 text-sm text-gray-400">登录您的账户以继续</p>
          </div>
        )}
      </div>

      <Card.Root className="w-full rounded-2xl border border-white/70 bg-white/92 shadow-xl shadow-slate-900/10 backdrop-blur-xl">
        <Card.Content className="p-6">
          {showSkeleton ? (
            <SkeletonBlock spec={formSkeleton} />
          ) : (
            <div className="qycw-content-fade flex flex-col gap-4">
              {/* Mode tabs (3 columns) */}
              <div className="relative grid grid-cols-3 rounded-xl bg-gray-100/80 p-1 text-sm">
                {MODES.map((m) => (
                  <button
                    key={m.key}
                    type="button"
                    onClick={() => setMode(m.key)}
                    className={`qycw-auth-mode relative z-10 rounded-lg py-2 font-medium transition-colors duration-200 ${
                      mode === m.key ? "qycw-auth-text-primary" : "qycw-auth-text-muted"
                    }`}
                  >
                    {m.label}
                  </button>
                ))}
                <span
                  aria-hidden
                  className="absolute top-1 bottom-1 left-1 w-[calc(33.3333%-0.1667rem)] rounded-lg bg-white shadow-sm transition-transform duration-300 ease-out"
                  style={{ transform: `translateX(${modeIndex * 100}%)` }}
                />
              </div>

              <form onSubmit={handleSubmit} className="flex flex-col gap-4">
                {mode === "password" && (
                  <>
                    <TextField.Root isRequired value={identifier} onChange={setIdentifier}>
                      <Label className="qycw-auth-text-muted text-xs font-medium">邮箱 / 用户名 / 手机号</Label>
                      <Input placeholder="请输入邮箱、用户名或手机号" className="mt-0.5" />
                    </TextField.Root>
                    <TextField.Root isRequired type="password" value={password} onChange={setPassword}>
                      <div className="flex items-center justify-between">
                        <Label className="qycw-auth-text-muted text-xs font-medium">密码</Label>
                        <span className="text-xs text-sky-500 hover:underline cursor-pointer">忘记密码？</span>
                      </div>
                      <Input placeholder="请输入密码" className="mt-0.5" />
                    </TextField.Root>
                  </>
                )}

                {mode === "email" && (
                  <>
                    <TextField.Root isRequired type="email" value={email} onChange={setEmail}>
                      <Label className="qycw-auth-text-muted text-xs font-medium">邮箱</Label>
                      <Input placeholder="you@example.com" className="mt-0.5" />
                    </TextField.Root>
                    <CodeRow
                      label="邮箱验证码"
                      code={code}
                      onCodeChange={setCode}
                      cooldown={cooldown}
                      sending={sendingCode}
                      onSend={handleSendCode}
                    />
                  </>
                )}

                {mode === "sms" && (
                  <>
                    <TextField.Root
                      isRequired
                      value={phone}
                      onChange={(v) => setPhone(v.replace(/\D/g, "").slice(0, 11))}
                    >
                      <Label className="qycw-auth-text-muted text-xs font-medium">手机号</Label>
                      <Input placeholder="11 位手机号" inputMode="numeric" maxLength={11} className="mt-0.5" />
                    </TextField.Root>
                    <CodeRow
                      label="短信验证码"
                      code={code}
                      onCodeChange={setCode}
                      cooldown={cooldown}
                      sending={sendingCode}
                      onSend={handleSendCode}
                    />
                  </>
                )}

                <Button
                  type="submit"
                  isDisabled={isLoading}
                  className="mt-1 w-full rounded-xl bg-sky-500 px-4 py-5 font-semibold !text-white shadow-md shadow-sky-200/70 transition-all duration-200 ease-out hover:-translate-y-0.5 hover:bg-sky-600 hover:shadow-lg hover:shadow-sky-300/70 active:translate-y-0 active:scale-[0.985] active:bg-sky-700 active:shadow-sm data-[disabled=true]:opacity-70 data-[disabled=true]:hover:translate-y-0 [&_*]:!text-white"
                >
                  {isLoading ? "登录中..." : "登录"}
                </Button>
              </form>

              {oauthProviders.length > 0 && (
                <div className="flex flex-col gap-2 pt-2">
                  <div className="flex items-center gap-2 text-xs text-gray-400">
                    <span className="flex-1 border-t border-gray-200" />
                    第三方登录
                    <span className="flex-1 border-t border-gray-200" />
                  </div>
                  {oauthProviders.map((p) => (
                    <Button
                      key={p.id}
                      type="button"
                      isDisabled={oauthLoading}
                      onPress={async () => {
                        setOAuthLoading(true)
                        try {
                          const redirectUri = `${window.location.origin}/api/v1/auth/oauth/${encodeURIComponent(p.id)}/callback`
                          const { url } = await getOAuthUrl(p.id, redirectUri)
                          window.location.href = url
                        } catch {
                          toast.error("获取登录地址失败，请稍后重试")
                          setOAuthLoading(false)
                        }
                      }}
                      className="w-full rounded-xl border border-gray-200 bg-white py-5 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50"
                    >
                      {oauthLoading ? "跳转中..." : `用 ${p.name} 登录`}
                    </Button>
                  ))}
                </div>
              )}
            </div>
          )}
        </Card.Content>
      </Card.Root>

      <p className="text-center text-sm text-gray-400">
        还没有账户？{" "}
        <Link to="/register" className="font-medium text-sky-500 hover:text-sky-600 transition-colors">
          立即注册
        </Link>
      </p>
    </div>
  )
}

function CodeRow({
  label,
  code,
  onCodeChange,
  cooldown,
  sending,
  onSend,
}: {
  label: string
  code: string
  onCodeChange: (v: string) => void
  cooldown: number
  sending: boolean
  onSend: () => void
}) {
  return (
    <div>
      <Label className="qycw-auth-text-muted text-xs font-medium">{label}</Label>
      <div className="mt-0.5 flex gap-2">
        <TextField.Root
          isRequired
          value={code}
          onChange={(v) => onCodeChange(v.replace(/\D/g, "").slice(0, 6))}
          aria-label={label}
          className="min-w-0 flex-1"
        >
          <Input placeholder="6 位数字" inputMode="numeric" maxLength={6} />
        </TextField.Root>
        <Button
          type="button"
          onPress={onSend}
          isDisabled={cooldown > 0 || sending}
          className="qycw-auth-text-strong h-10 shrink-0 whitespace-nowrap rounded-xl bg-white px-3 text-xs font-medium shadow-sm shadow-gray-100/60 transition-all duration-200 ease-out hover:bg-gray-50 active:bg-gray-100 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-60"
        >
          {sending ? "发送中..." : cooldown > 0 ? `${cooldown}s 后重试` : "获取验证码"}
        </Button>
      </div>
    </div>
  )
}
