import { useCallback, useEffect, useState } from 'react'
import Alert from '@mui/material/Alert'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Chip from '@mui/material/Chip'
import Divider from '@mui/material/Divider'
import FormControl from '@mui/material/FormControl'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import Select from '@mui/material/Select'
import Stack from '@mui/material/Stack'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import { createAvatar } from '@dicebear/core'
import { useMutation } from '@tanstack/react-query'
import { useUnit } from 'effector-react'
import { useForm } from 'react-hook-form'
import { AVATAR_STYLES, DEFAULT_STYLE_ID, getStyleById } from '@/shared/lib/avatar-styles'
import {
  $requestEmailChangeCodeError,
  $updateProfileError,
  $user,
  $verifyEmailChangeError,
  fetchAuthMethodsFx,
  requestEmailChangeCodeFx,
  setPasswordFx,
  unlinkOAuthFx,
  updateProfileFx,
  verifyEmailChangeFx,
  type AuthMethod,
} from '@/shared/model/auth'
import { UserAvatar } from '@/shared/ui/UserAvatar'
import { apiClient } from '@/shared/api/client'
import type { AxiosError } from 'axios'

function getApiErrorMessage(error: unknown): string | null {
  const e = error as AxiosError<{ error?: string }>
  const msg = e?.response?.data?.error
  return msg ? String(msg) : null
}

export function SettingsPage() {
  const user = useUnit($user)
  const pendingEmailReq = useUnit(requestEmailChangeCodeFx.pending)
  const pendingEmailVerify = useUnit(verifyEmailChangeFx.pending)
  const pendingProfile = useUnit(updateProfileFx.pending)
  const errorEmailReq = useUnit($requestEmailChangeCodeError)
  const errorProfile = useUnit($updateProfileError)
  const errorEmailVerify = useUnit($verifyEmailChangeError)

  const emailForm = useForm<{ newEmail: string; code: string }>({
    defaultValues: { newEmail: '', code: '' },
    mode: 'onChange',
  })

  const profileForm = useForm<{ displayName: string }>({
    defaultValues: {
      displayName: user?.displayName ? String(user.displayName) : '',
    },
    mode: 'onChange',
  })

  const emailErrorMsg = getApiErrorMessage(errorEmailReq) ?? getApiErrorMessage(errorEmailVerify)
  const profileErrorMsg = getApiErrorMessage(errorProfile)

  const [selectedStyle, setSelectedStyle] = useState(user?.avatarStyle || DEFAULT_STYLE_ID)
  const [previewSrc, setPreviewSrc] = useState<string | null>(null)
  const [previewStyle, setPreviewStyle] = useState<string>(DEFAULT_STYLE_ID)

  const hasUnsavedPreview = previewSrc !== null

  const [authMethods, setAuthMethods] = useState<AuthMethod[]>([])
  const [showSetPassword, setShowSetPassword] = useState(false)
  const passwordForm = useForm<{ password: string; passwordConfirm: string }>({
    defaultValues: { password: '', passwordConfirm: '' },
  })

  useEffect(() => {
    fetchAuthMethodsFx()
      .then(setAuthMethods)
      .catch(() => {
        setAuthMethods([])
      })
  }, [])

  const setPasswordMutation = useMutation({
    mutationFn: async (pw: string) => {
      await setPasswordFx(pw)
      const methods = await fetchAuthMethodsFx()
      setAuthMethods(methods)
      setShowSetPassword(false)
    },
    onError: () => {},
  })

  const unlinkMutation = useMutation({
    mutationFn: async (provider: 'vk' | 'yandex') => {
      await unlinkOAuthFx(provider)
      const methods = await fetchAuthMethodsFx()
      setAuthMethods(methods)
    },
    onError: () => {},
  })

  const [showChangePassword, setShowChangePassword] = useState(false)
  const changePasswordForm = useForm<{ oldPassword: string; newPassword: string; confirmPassword: string }>({
    defaultValues: { oldPassword: '', newPassword: '', confirmPassword: '' },
  })

  const changePasswordMutation = useMutation({
    mutationFn: async (params: { oldPassword: string; newPassword: string }) => {
      await apiClient.post('me/change-password', params)
    },
    onSuccess: () => {
      setShowChangePassword(false)
      changePasswordForm.reset()
    },
  })

  const linkedCount = useCallback(() => {
    return authMethods.filter((m) => m.active).length
  }, [authMethods])

  const METHOD_LABELS: Record<string, string> = { password: 'Пароль', vk: 'ВКонтакте', yandex: 'Яндекс' }

  if (!user) {
    return <Alert severity="info">Нужно войти. Перейдите на страницу «Вход».</Alert>
  }

  return (
    <Box>
      <Typography variant="h4" gutterBottom>
        Настройки
      </Typography>
      <Typography color="text.secondary" sx={{ mb: 3 }}>
        Текущая почта: <b>{user.email}</b>
      </Typography>

      {emailErrorMsg && (
        <Alert severity="error" sx={{ mb: 2 }}>
          {emailErrorMsg}
        </Alert>
      )}
      {profileErrorMsg && (
        <Alert severity="error" sx={{ mb: 2 }}>
          {profileErrorMsg}
        </Alert>
      )}

      <Stack spacing={3} sx={{ maxWidth: 560 }}>
        <Box>
          <Typography variant="h6" gutterBottom>
            Профиль
          </Typography>
          <Stack spacing={2}>
            <TextField
              label="Имя или ник"
              helperText="До 40 символов"
              slotProps={{ htmlInput: { maxLength: 40 } }}
              {...profileForm.register('displayName')}
            />
            <Button
              variant="contained"
              disabled={pendingProfile}
              onClick={() => {
                const raw = profileForm.getValues('displayName')
                const name = raw.trim()
                updateProfileFx({ displayName: name.length ? name : null })
              }}
            >
              Сохранить
            </Button>
          </Stack>
        </Box>

        <Divider />

        <Box>
          <Typography variant="h6" gutterBottom>
            Аватар
          </Typography>

          <Stack direction="row" spacing={3} sx={{ alignItems: 'flex-start', mb: 2 }}>
            <Box sx={{ textAlign: 'center' }}>
              <UserAvatar
                userId={user.id}
                avatarUrl={hasUnsavedPreview ? previewSrc : user.avatar}
                avatarStyle={hasUnsavedPreview ? previewStyle : user.avatarStyle}
                size={80}
                sx={{
                  border: 2,
                  borderColor: hasUnsavedPreview ? 'warning.main' : 'primary.main',
                }}
              />
              <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.5 }}>
                {hasUnsavedPreview ? 'Предпросмотр' : user.avatar ? 'Сохранён' : 'Авто'}
              </Typography>
            </Box>
            {hasUnsavedPreview && (
              <Box sx={{ textAlign: 'center' }}>
                <UserAvatar
                  userId={user.id}
                  avatarUrl={user.avatar}
                  avatarStyle={user.avatarStyle}
                  size={80}
                  sx={{ border: 2, borderColor: 'divider', opacity: 0.6 }}
                />
                <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.5 }}>
                  Текущий
                </Typography>
              </Box>
            )}
          </Stack>

          <Stack direction="row" spacing={1} sx={{ flexWrap: 'wrap', gap: 1, mb: 1 }}>
            <FormControl size="small" sx={{ minWidth: 140 }}>
              <InputLabel>Стиль</InputLabel>
              <Select value={selectedStyle} label="Стиль" onChange={(e) => setSelectedStyle(e.target.value)}>
                {AVATAR_STYLES.map((s) => (
                  <MenuItem key={s.id} value={s.id}>
                    {s.label}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
            <Button
              variant="outlined"
              onClick={() => {
                const seed = `${user.id}_${Date.now()}`
                const styleDef = getStyleById(selectedStyle)
                const avatar = createAvatar(styleDef.style, { seed })
                setPreviewSrc(avatar.toDataUri())
                setPreviewStyle(selectedStyle)
              }}
            >
              Сгенерировать
            </Button>
          </Stack>

          {hasUnsavedPreview && (
            <Stack direction="row" spacing={1} sx={{ flexWrap: 'wrap', gap: 1, mb: 1 }}>
              <Button
                variant="contained"
                disabled={pendingProfile}
                onClick={() => {
                  updateProfileFx({
                    displayName: user.displayName?.trim() || null,
                    avatar: previewSrc,
                    avatarStyle: previewStyle,
                  })
                  setPreviewSrc(null)
                }}
              >
                Сохранить
              </Button>
              <Button variant="text" onClick={() => setPreviewSrc(null)}>
                Отмена
              </Button>
            </Stack>
          )}
        </Box>

        {!user.isAdmin && (
          <>
            <Divider />
            <Box>
              <Typography variant="h6" gutterBottom>
                Методы входа
              </Typography>
              <Stack spacing={1}>
                {authMethods.map((m) => (
                  <Stack key={m.type} direction="row" spacing={2} sx={{ alignItems: 'center' }}>
                    <Typography sx={{ minWidth: 120 }}>{METHOD_LABELS[m.type] || m.type}</Typography>
                    <Chip
                      label={m.active ? 'Привязан' : 'Не привязан'}
                      color={m.active ? 'success' : 'default'}
                      size="small"
                    />
                    {m.active && m.type !== 'password' && (
                      <Button
                        size="small"
                        variant="outlined"
                        color="error"
                        disabled={linkedCount() <= 1}
                        onClick={() => unlinkMutation.mutate(m.type as 'vk' | 'yandex')}
                      >
                        Отвязать
                      </Button>
                    )}
                    {m.active && m.type === 'password' && (
                      <Button size="small" variant="outlined" onClick={() => setShowChangePassword(true)}>
                        Сменить пароль
                      </Button>
                    )}
                    {!m.active && m.type === 'password' && (
                      <Button size="small" variant="outlined" onClick={() => setShowSetPassword(true)}>
                        Установить пароль
                      </Button>
                    )}
                    {!m.active && m.type !== 'password' && (
                      <Button
                        size="small"
                        variant="outlined"
                        component="a"
                        href={`/api/auth/oauth/${m.type}/link?token=${localStorage.getItem('craftshop_auth_token') || ''}`}
                      >
                        Привязать
                      </Button>
                    )}
                  </Stack>
                ))}
              </Stack>

              {showSetPassword && (
                <Stack spacing={2} sx={{ mt: 2, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 }}>
                  <TextField label="Пароль" type="password" {...passwordForm.register('password')} fullWidth />
                  <TextField
                    label="Подтверждение пароля"
                    type="password"
                    {...passwordForm.register('passwordConfirm')}
                    fullWidth
                    error={
                      Boolean(passwordForm.watch('passwordConfirm')) &&
                      passwordForm.watch('password') !== passwordForm.watch('passwordConfirm')
                    }
                    helperText={
                      passwordForm.watch('passwordConfirm') &&
                      passwordForm.watch('password') !== passwordForm.watch('passwordConfirm')
                        ? 'Пароли не совпадают'
                        : null
                    }
                  />
                  <Stack direction="row" spacing={1}>
                    <Button
                      variant="contained"
                      disabled={
                        !passwordForm.watch('password') ||
                        passwordForm.watch('password').length < 8 ||
                        passwordForm.watch('password') !== passwordForm.watch('passwordConfirm') ||
                        setPasswordMutation.isPending
                      }
                      onClick={() => setPasswordMutation.mutate(passwordForm.getValues('password'))}
                    >
                      Сохранить
                    </Button>
                    <Button variant="text" onClick={() => setShowSetPassword(false)}>
                      Отмена
                    </Button>
                  </Stack>
                </Stack>
              )}

              {showChangePassword && (
                <Stack spacing={2} sx={{ mt: 2, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 }}>
                  <TextField
                    label="Текущий пароль"
                    type="password"
                    {...changePasswordForm.register('oldPassword')}
                    fullWidth
                  />
                  <TextField
                    label="Новый пароль"
                    type="password"
                    {...changePasswordForm.register('newPassword')}
                    fullWidth
                  />
                  <TextField
                    label="Подтверждение пароля"
                    type="password"
                    {...changePasswordForm.register('confirmPassword')}
                    fullWidth
                    error={
                      Boolean(changePasswordForm.watch('confirmPassword')) &&
                      changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword')
                    }
                    helperText={
                      changePasswordForm.watch('confirmPassword') &&
                      changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword')
                        ? 'Пароли не совпадают'
                        : null
                    }
                  />
                  <Stack direction="row" spacing={1}>
                    <Button
                      variant="contained"
                      disabled={
                        !changePasswordForm.watch('oldPassword') ||
                        !changePasswordForm.watch('newPassword') ||
                        changePasswordForm.watch('newPassword').length < 8 ||
                        changePasswordForm.watch('newPassword') !== changePasswordForm.watch('confirmPassword') ||
                        changePasswordMutation.isPending
                      }
                      onClick={() =>
                        changePasswordMutation.mutate({
                          oldPassword: changePasswordForm.getValues('oldPassword'),
                          newPassword: changePasswordForm.getValues('newPassword'),
                        })
                      }
                    >
                      Сохранить
                    </Button>
                    <Button variant="text" onClick={() => setShowChangePassword(false)}>
                      Отмена
                    </Button>
                  </Stack>
                </Stack>
              )}
            </Box>
          </>
        )}

        <Divider />

        <Box>
          <Typography variant="h6" gutterBottom>
            Смена почты
          </Typography>
          <Stack spacing={2}>
            <TextField label="Новая почта" {...emailForm.register('newEmail')} />
            <Button
              variant="outlined"
              disabled={!emailForm.watch('newEmail') || pendingEmailReq}
              onClick={() => requestEmailChangeCodeFx(emailForm.getValues('newEmail').trim())}
            >
              Отправить код на новую почту
            </Button>
            <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
              <TextField label="Код (6 цифр)" inputMode="numeric" {...emailForm.register('code')} />
              <Button
                variant="contained"
                disabled={emailForm.watch('code').trim().length !== 6 || pendingEmailVerify}
                onClick={() =>
                  verifyEmailChangeFx({
                    newEmail: emailForm.getValues('newEmail').trim(),
                    code: emailForm.getValues('code').trim(),
                  })
                }
              >
                Подтвердить
              </Button>
            </Stack>
          </Stack>
        </Box>
      </Stack>
    </Box>
  )
}
