import { type FormEvent, useEffect, useState } from 'react'
import { Link, useMatch, useNavigate, useParams } from 'react-router-dom'
import { checkUserEmailAvailable, fetchUser, requestUserEmailChange, saveUser } from '../../api/session'
import { ApiHttpError } from '../../api/http'
import type { UserListRow } from '../../api/types'
import { useAuth } from '../../auth/AuthProvider'
import { isParentPortalRole, isTeacherPortalRole } from '../../lib/portalRoles'

function portalDashboardPath(role: string) {
  if (isParentPortalRole(role)) return '/app/parent/home'
  if (isTeacherPortalRole(role)) return '/app/teacher_dashboard'
  return '/app/home'
}

function sameEmail(a: string, b: string): boolean {
  return a.trim().toLowerCase() === b.trim().toLowerCase()
}

const EMAIL_IN_USE_FALLBACK = 'This email is already in use. Please use a different email address.'

function errorMessageFromApi(err: unknown, fallback: string): string {
  if (err instanceof ApiHttpError) {
    const b = err.body
    if (b && typeof b === 'object' && b !== null) {
      const o = b as Record<string, unknown>
      if (typeof o.message === 'string' && o.message.trim()) return o.message.trim()
      const errors = o.errors
      if (errors && typeof errors === 'object' && errors !== null) {
        const em = (errors as Record<string, unknown>).email
        if (Array.isArray(em) && em[0] != null) return String(em[0])
        if (typeof em === 'string' && em.trim()) return em.trim()
      }
    }
    if (err.message.trim()) return err.message
  }
  if (err instanceof Error && err.message.trim()) return err.message
  return fallback
}

function rowToForm(row: UserListRow) {
  const u = row.user ?? {}
  return {
    password: '',
    firstname: String(u.firstname ?? ''),
    lastname: String(u.lastname ?? ''),
    cellphone: String(u.cellphone ?? ''),
    email: String(u.email ?? ''),
    address_street: String(u.address_street ?? ''),
    city: String(u.city ?? ''),
    state: String(u.state ?? ''),
    zip: String(u.zip ?? ''),
  }
}

/** CI `user/edit.php` — simplified standalone edit (`POST` parity via API). */
export function UserEditPage() {
  const portalSelf = useMatch({ path: '/app/account', end: true })
  const { userId } = useParams()
  const { user, selectedRole, roles } = useAuth()
  const role = selectedRole ?? roles[0] ?? ''
  const id = portalSelf ? Number(user?.id ?? 0) : Number(userId ?? 0)
  const navigate = useNavigate()
  const [error, setError] = useState<string | null>(null)
  const [loadError, setLoadError] = useState<string | null>(null)
  const [reloadKey, setReloadKey] = useState(0)
  const [loading, setLoading] = useState(() => id > 0)
  const [showPassword, setShowPassword] = useState(false)
  /** Email currently stored on the account (from API). Used for portal email-change flow. */
  const [verifiedEmail, setVerifiedEmail] = useState('')
  const [emailChangeNotice, setEmailChangeNotice] = useState<string | null>(null)
  const [form, setForm] = useState({
    password: '',
    firstname: '',
    lastname: '',
    cellphone: '',
    email: '',
    address_street: '',
    city: '',
    state: '',
    zip: '',
  })

  useEffect(() => {
    if (!id) {
      setLoading(false)
      setLoadError(null)
      return
    }
    let cancelled = false
    setLoading(true)
    setLoadError(null)
    void fetchUser(id)
      .then((row) => {
        if (!cancelled) {
          setShowPassword(false)
          const next = rowToForm(row)
          setForm(next)
          setVerifiedEmail(String(row.user?.email ?? next.email ?? ''))
          setEmailChangeNotice(null)
        }
      })
      .catch((err) => {
        if (!cancelled) {
          setLoadError(err instanceof Error ? err.message : 'Unable to load user.')
        }
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [id, reloadKey])

  async function onSubmit(e: FormEvent) {
    e.preventDefault()
    if (!id) return
    setError(null)
    try {
      setEmailChangeNotice(null)
      const emailChanged = !sameEmail(form.email, verifiedEmail)
      const newEmail = form.email.trim()

      if (emailChanged) {
        try {
          const avail = await checkUserEmailAvailable(id, newEmail)
          if (avail.available === false) {
            setError(
              (typeof avail.message === 'string' && avail.message.trim()) || EMAIL_IN_USE_FALLBACK,
            )
            return
          }
        } catch (err) {
          if (err instanceof ApiHttpError) {
            if (err.status === 404) {
              /* availability route optional — continue; duplicate may still be rejected below */
            } else if (err.status === 422 || err.status === 409) {
              setError(errorMessageFromApi(err, EMAIL_IN_USE_FALLBACK))
              return
            } else {
              setError(err.message || 'Could not verify email. Try again.')
              return
            }
          } else {
            setError('Could not verify email. Try again.')
            return
          }
        }
      }

      const payload: Record<string, unknown> = {
        firstname: form.firstname,
        lastname: form.lastname,
        cellphone: form.cellphone,
        address_street: form.address_street,
        city: form.city,
        state: form.state,
        zip: form.zip,
      }
      if (emailChanged) {
        if (!portalSelf) payload.email = form.email
      } else {
        payload.email = form.email
      }
      if (form.password.trim()) payload.password = form.password

      if (portalSelf && emailChanged) {
        await requestUserEmailChange(id, newEmail)
        await saveUser(id, payload)
        setEmailChangeNotice(
          `We sent a confirmation link to ${newEmail}. Your sign-in email stays ${verifiedEmail.trim() || 'unchanged'} until you open that link.`,
        )
        setForm((c) => ({ ...c, email: verifiedEmail, password: '' }))
        setShowPassword(false)
        return
      }

      await saveUser(id, payload)
      if (portalSelf) {
        navigate(portalDashboardPath(role), { replace: true })
      } else {
        navigate('/app/user/user-list')
      }
    } catch (err) {
      if (err instanceof ApiHttpError && (err.status === 422 || err.status === 409)) {
        setError(errorMessageFromApi(err, EMAIL_IN_USE_FALLBACK))
        return
      }
      setError(errorMessageFromApi(err, 'Update failed.'))
    }
  }

  if (portalSelf && !user?.id) {
    return (
      <div className="container mt-4">
        <div className="alert alert-warning">You need to be signed in to open account settings.</div>
        <Link to="/login">Log in</Link>
      </div>
    )
  }

  return (
    <div className="container mt-4">
      <h1 className="h3 mb-4">{portalSelf ? 'Account settings' : 'Edit User'}</h1>
      <p className="text-muted small">
        {portalSelf
          ? 'Update your profile and password. If you change your email, we send a confirmation link to the new address; it only updates after you click that link.'
          : 'Profile fields are loaded from the server. Save to apply changes.'}
      </p>
      {emailChangeNotice ? (
        <div className="alert alert-success" role="status">
          {emailChangeNotice}
        </div>
      ) : null}
      {loadError ? (
        <div
          className="alert alert-danger d-flex flex-wrap align-items-center justify-content-between gap-2"
          role="alert"
        >
          <span>{loadError}</span>
          <button
            type="button"
            className="btn btn-outline-danger btn-sm"
            onClick={() => setReloadKey((k) => k + 1)}
          >
            Try again
          </button>
        </div>
      ) : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted" aria-busy="true">
          Loading profile…
        </p>
      ) : null}
      {!loading && !loadError ? (
        <form onSubmit={(e) => void onSubmit(e)} className="row g-3" style={{ maxWidth: 560 }}>
        <div className="col-12">
          <label className="form-label" htmlFor="user-edit-password">
            New Password (leave blank to keep)
          </label>
          <div className="input-group">
            <input
              id="user-edit-password"
              type={showPassword ? 'text' : 'password'}
              className="form-control"
              autoComplete="new-password"
              value={form.password}
              onChange={(e) => setForm((c) => ({ ...c, password: e.target.value }))}
            />
            <button
              type="button"
              className="btn btn-outline-secondary"
              aria-label={showPassword ? 'Hide password' : 'Show password'}
              aria-pressed={showPassword}
              onClick={() => setShowPassword((v) => !v)}
            >
              <i className={showPassword ? 'bi bi-eye-slash' : 'bi bi-eye'} aria-hidden />
            </button>
          </div>
        </div>
        <div className="col-md-6">
          <label className="form-label">First Name</label>
          <input
            className="form-control"
            required
            value={form.firstname}
            onChange={(e) => setForm((c) => ({ ...c, firstname: e.target.value }))}
          />
        </div>
        <div className="col-md-6">
          <label className="form-label">Last Name</label>
          <input
            className="form-control"
            required
            value={form.lastname}
            onChange={(e) => setForm((c) => ({ ...c, lastname: e.target.value }))}
          />
        </div>
        <div className="col-12">
          <label className="form-label">Cell Phone</label>
          <input
            className="form-control"
            required
            value={form.cellphone}
            onChange={(e) => setForm((c) => ({ ...c, cellphone: e.target.value }))}
          />
        </div>
        <div className="col-12">
          <label className="form-label" htmlFor="user-edit-email">
            Email
          </label>
          <input
            id="user-edit-email"
            type="email"
            className="form-control"
            required
            autoComplete="email"
            value={form.email}
            onChange={(e) => setForm((c) => ({ ...c, email: e.target.value }))}
          />
          {portalSelf ? (
            <p className="form-text small mb-0">
              Changing this address sends a confirmation link to the new email. It is not saved until you confirm.
            </p>
          ) : null}
        </div>
        <div className="col-12">
          <label className="form-label">Address Street</label>
          <input
            className="form-control"
            required
            value={form.address_street}
            onChange={(e) => setForm((c) => ({ ...c, address_street: e.target.value }))}
          />
        </div>
        <div className="col-md-6">
          <label className="form-label">City</label>
          <input
            className="form-control"
            required
            value={form.city}
            onChange={(e) => setForm((c) => ({ ...c, city: e.target.value }))}
          />
        </div>
        <div className="col-md-3">
          <label className="form-label">State</label>
          <input
            className="form-control"
            required
            value={form.state}
            onChange={(e) => setForm((c) => ({ ...c, state: e.target.value }))}
          />
        </div>
        <div className="col-md-3">
          <label className="form-label">Zip</label>
          <input
            className="form-control"
            required
            value={form.zip}
            onChange={(e) => setForm((c) => ({ ...c, zip: e.target.value }))}
          />
        </div>
        <div className="col-12">
          <button type="submit" className="btn btn-primary me-2">
            Update
          </button>
          <Link
            className="btn btn-outline-secondary"
            to={portalSelf ? portalDashboardPath(role) : '/app/user/user-list'}
          >
            Cancel
          </Link>
        </div>
      </form>
      ) : null}
    </div>
  )
}
