'use client'

import { useCallback, useEffect, useId, useRef, useState } from 'react'
import type { TFunction } from 'i18next'
import { FiCamera, FiSettings, FiX } from 'react-icons/fi'
import { resolveMediaUrl } from '@/lib/media/resolveMediaUrl'
import { hasValidImageSrc } from '@/lib/media/mediaGuards'
import { GROUP_NAME_MAX_LENGTH } from '@/lib/groups/groupSettings'

const IMAGE_MAX_BYTES = 2 * 1024 * 1024

function SettingsToggle({
    checked,
    onChange,
    disabled,
}: {
    checked: boolean
    onChange: (v: boolean) => void
    disabled?: boolean
}) {
    return (
        <button
            type="button"
            role="switch"
            aria-checked={checked}
            disabled={disabled}
            onClick={() => !disabled && onChange(!checked)}
            className={`relative inline-flex h-7 w-12 shrink-0 rounded-full transition-colors duration-200 ease-out focus:outline-none ${
                disabled ? 'cursor-default opacity-70' : 'cursor-pointer'
            } ${checked ? 'bg-gray-900 dark:bg-white' : 'bg-slate-300 dark:bg-gray-600'}`}
        >
            <span
                className={`pointer-events-none mt-0.5 ml-0.5 inline-block h-6 w-6 rounded-full bg-white shadow-sm transition-transform duration-200 ease-out dark:bg-gray-900 ${
                    checked ? 'translate-x-5' : 'translate-x-0'
                }`}
            />
        </button>
    )
}

function readFileAsDataUrl(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.onload = () => resolve(String(reader.result ?? ''))
        reader.onerror = () => reject(reader.error)
        reader.readAsDataURL(file)
    })
}

export type GroupFamilySettingsInitial = {
    name: string
    avatar: string | null
    banner: string | null
    isCanApplicapplication: boolean
}

export default function GroupFamilySettingsModal({
    isOpen,
    closing,
    entering,
    onClose,
    groupId,
    initial,
    t,
    onSaved,
}: {
    isOpen: boolean
    closing: boolean
    entering: boolean
    onClose: () => void
    groupId: string
    initial: GroupFamilySettingsInitial
    t: TFunction
    onSaved: () => void | Promise<void>
}) {
    const nameId = useId()
    const avatarInputRef = useRef<HTMLInputElement>(null)
    const bannerInputRef = useRef<HTMLInputElement>(null)

    const [draftName, setDraftName] = useState(initial.name)
    const [draftCanApply, setDraftCanApply] = useState(initial.isCanApplicapplication)
    const [avatarPreview, setAvatarPreview] = useState<string | null>(null)
    const [bannerPreview, setBannerPreview] = useState<string | null>(null)
    const [pendingAvatarFile, setPendingAvatarFile] = useState<File | null>(null)
    const [pendingBannerFile, setPendingBannerFile] = useState<File | null>(null)
    const [bannerRemoved, setBannerRemoved] = useState(false)
    const [saving, setSaving] = useState(false)
    const [formError, setFormError] = useState('')

    const resetDraft = useCallback(() => {
        setDraftName(initial.name)
        setDraftCanApply(initial.isCanApplicapplication)
        setPendingAvatarFile(null)
        setPendingBannerFile(null)
        setBannerRemoved(false)
        setAvatarPreview(null)
        setBannerPreview(null)
        setFormError('')
    }, [initial])

    useEffect(() => {
        if (isOpen) {
            resetDraft()
        }
    }, [isOpen, resetDraft])

    const displayAvatar = avatarPreview ?? resolveMediaUrl(initial.avatar)
    const displayBanner = bannerRemoved
        ? null
        : bannerPreview ?? resolveMediaUrl(initial.banner)
    const canDeleteBanner = hasValidImageSrc(displayBanner)

    const validateImageFile = (file: File): string | null => {
        if (!file.type.startsWith('image/')) {
            return t('familys.settings.errors.imageInvalidType')
        }
        if (file.size > IMAGE_MAX_BYTES) {
            return t('familys.settings.errors.imageTooLarge')
        }
        return null
    }

    const handleAvatarPick = (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0]
        e.target.value = ''
        if (!file) return
        const err = validateImageFile(file)
        if (err) {
            setFormError(err)
            return
        }
        if (avatarPreview?.startsWith('blob:')) {
            URL.revokeObjectURL(avatarPreview)
        }
        setFormError('')
        setPendingAvatarFile(file)
        setAvatarPreview(URL.createObjectURL(file))
    }

    const handleBannerPick = (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0]
        e.target.value = ''
        if (!file) return
        const err = validateImageFile(file)
        if (err) {
            setFormError(err)
            return
        }
        if (bannerPreview?.startsWith('blob:')) {
            URL.revokeObjectURL(bannerPreview)
        }
        setFormError('')
        setBannerRemoved(false)
        setPendingBannerFile(file)
        setBannerPreview(URL.createObjectURL(file))
    }

    const handleDeleteBanner = () => {
        if (bannerPreview?.startsWith('blob:')) {
            URL.revokeObjectURL(bannerPreview)
        }
        setFormError('')
        setPendingBannerFile(null)
        setBannerPreview(null)
        setBannerRemoved(true)
    }

    const handleSave = async () => {
        const name = draftName.trim()
        if (!name) {
            setFormError(t('familys.settings.errors.nameRequired'))
            return
        }
        if (name.length > GROUP_NAME_MAX_LENGTH) {
            setFormError(t('familys.settings.errors.nameTooLong'))
            return
        }

        setSaving(true)
        setFormError('')
        try {
            const body: Record<string, unknown> = {
                name,
                isCanApplicapplication: draftCanApply,
            }
            if (pendingAvatarFile) {
                body.avatarUrl = await readFileAsDataUrl(pendingAvatarFile)
            }
            if (pendingBannerFile) {
                body.bannerUrl = await readFileAsDataUrl(pendingBannerFile)
            } else if (bannerRemoved) {
                body.removeBanner = true
            }

            const res = await fetch(`/api/group/${encodeURIComponent(groupId)}`, {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                credentials: 'include',
                body: JSON.stringify(body),
            })
            const json = (await res.json()) as { ok?: boolean; message?: string }
            if (!res.ok || !json.ok) {
                setFormError(json.message || t('familys.settings.saveFailed'))
                return
            }
            await onSaved()
            onClose()
        } catch {
            setFormError(t('familys.settings.saveFailed'))
        } finally {
            setSaving(false)
        }
    }

    if (!isOpen) return null

    return (
        <div
            className={`fixed inset-0 z-[600] flex items-center justify-center p-3 transition-opacity duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] ${closing || entering ? 'pointer-events-none opacity-0' : 'opacity-100'}`}
        >
            <div className="absolute inset-0 bg-black/60" onClick={onClose} aria-hidden />
            <div
                role="dialog"
                aria-modal="true"
                aria-labelledby="group-settings-title"
                className={`relative flex max-h-[min(90vh,720px)] w-full max-w-lg flex-col overflow-hidden rounded-xl border border-gray-200 bg-white shadow-2xl transition-[opacity,transform] duration-200 ease-[cubic-bezier(0.56,0.12,0.12,0.98)] dark:border-gray-800 dark:bg-[#0c0d0e] ${closing || entering ? 'scale-95 opacity-0' : 'scale-100 opacity-100'}`}
            >
                <div className="flex shrink-0 items-center justify-between gap-3 border-b border-gray-100 px-5 py-4 dark:border-white/10">
                    <h3
                        id="group-settings-title"
                        className="flex min-w-0 items-center gap-2 text-lg font-semibold text-gray-900 dark:text-white"
                    >
                        <FiSettings
                            className="h-5 w-5 shrink-0 text-gray-500 dark:text-gray-400"
                            aria-hidden
                        />
                        <span className="truncate">{t('familys.settings.modalTitle')}</span>
                    </h3>
                    <button
                        type="button"
                        onClick={onClose}
                        disabled={saving}
                        className="inline-flex h-8 w-8 items-center justify-center rounded-full text-gray-500 transition-colors hover:bg-gray-100 disabled:opacity-50 dark:text-gray-300 dark:hover:bg-[#1a1c21]"
                        aria-label={t('common.close')}
                    >
                        <FiX className="h-4.5 w-4.5" aria-hidden />
                    </button>
                </div>

                <div className="min-h-0 flex-1 overflow-y-auto px-5 py-4">
                    <div className="space-y-5">
                        <div>
                            <label
                                htmlFor={nameId}
                                className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-200"
                            >
                                {t('familys.settings.nameLabel')}
                            </label>
                            <input
                                id={nameId}
                                type="text"
                                value={draftName}
                                maxLength={GROUP_NAME_MAX_LENGTH}
                                disabled={saving}
                                onChange={(e) => setDraftName(e.target.value)}
                                placeholder={t('familys.settings.namePlaceholder')}
                                className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm text-gray-900 outline-none ring-0 transition-colors focus:border-gray-400 disabled:opacity-60 dark:border-white/15 dark:bg-black/30 dark:text-white dark:focus:border-white/35"
                            />
                        </div>

                        <div>
                            <p className="mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-200">
                                {t('familys.settings.avatarLabel')}
                            </p>
                            <div className="flex items-center gap-4">
                                <div className="relative h-20 w-20 shrink-0 overflow-hidden rounded-2xl border border-gray-200 bg-gray-100 dark:border-white/15 dark:bg-neutral-800">
                                    {hasValidImageSrc(displayAvatar) ? (
                                        // eslint-disable-next-line @next/next/no-img-element
                                        <img
                                            src={displayAvatar}
                                            alt=""
                                            className="h-full w-full object-cover"
                                        />
                                    ) : (
                                        <span className="flex h-full w-full items-center justify-center text-gray-400">
                                            <FiCamera className="h-7 w-7" aria-hidden />
                                        </span>
                                    )}
                                </div>
                                <button
                                    type="button"
                                    disabled={saving}
                                    onClick={() => avatarInputRef.current?.click()}
                                    className="rounded-lg border border-gray-200 px-3 py-2 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:opacity-50 dark:border-white/20 dark:text-gray-200 dark:hover:bg-white/10"
                                >
                                    {t('familys.settings.changeAvatar')}
                                </button>
                                <input
                                    ref={avatarInputRef}
                                    type="file"
                                    accept="image/*"
                                    className="hidden"
                                    onChange={handleAvatarPick}
                                />
                            </div>
                            <p className="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
                                {t('familys.settings.imageHint')}
                            </p>
                        </div>

                        <div>
                            <p className="mb-1.5 text-sm font-medium text-gray-700 dark:text-gray-200">
                                {t('familys.settings.bannerLabel')}
                            </p>
                            <div className="relative overflow-hidden rounded-xl border border-gray-200 bg-gray-100 dark:border-white/15 dark:bg-neutral-800">
                                <div
                                    className="h-28 w-full bg-cover bg-center sm:h-32"
                                    style={
                                        hasValidImageSrc(displayBanner)
                                            ? { backgroundImage: `url("${displayBanner}")` }
                                            : undefined
                                    }
                                />
                                <div className="absolute bottom-2 right-2 flex flex-col items-stretch gap-1.5">
                                    {canDeleteBanner ? (
                                        <button
                                            type="button"
                                            disabled={saving}
                                            onClick={handleDeleteBanner}
                                            className="rounded-lg border border-red-200/90 bg-white/90 px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-colors hover:bg-red-50 disabled:opacity-50 dark:border-red-500/30 dark:bg-black/60 dark:text-red-400 dark:hover:bg-red-950/40"
                                        >
                                            {t('familys.settings.deleteBanner')}
                                        </button>
                                    ) : null}
                                    <button
                                        type="button"
                                        disabled={saving}
                                        onClick={() => bannerInputRef.current?.click()}
                                        className="rounded-lg border border-gray-200/80 bg-white/90 px-3 py-1.5 text-xs font-medium text-gray-700 shadow-sm transition-colors hover:bg-white disabled:opacity-50 dark:border-white/20 dark:bg-black/60 dark:text-gray-100 dark:hover:bg-black/80"
                                    >
                                        {t('familys.settings.changeBanner')}
                                    </button>
                                </div>
                                <input
                                    ref={bannerInputRef}
                                    type="file"
                                    accept="image/*"
                                    className="hidden"
                                    onChange={handleBannerPick}
                                />
                            </div>
                            <p className="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
                                {t('familys.settings.imageHint')}
                            </p>
                        </div>

                        <div className="flex items-center justify-between gap-4 rounded-xl border border-gray-100 bg-gray-50/80 px-4 py-3.5 dark:border-white/10 dark:bg-white/[0.03]">
                            <div className="min-w-0">
                                <p className="text-sm font-medium text-gray-900 dark:text-white">
                                    {t('familys.settings.allowApplicationLabel')}
                                </p>
                                <p className="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
                                    {t('familys.settings.allowApplicationDesc')}
                                </p>
                            </div>
                            <SettingsToggle
                                checked={draftCanApply}
                                onChange={setDraftCanApply}
                                disabled={saving}
                            />
                        </div>

                        {formError ? (
                            <p className="text-sm text-red-600 dark:text-red-400" role="alert">
                                {formError}
                            </p>
                        ) : null}
                    </div>
                </div>

                <div className="flex shrink-0 items-center justify-end gap-2 border-t border-gray-100 px-5 py-4 dark:border-white/10">
                    <button
                        type="button"
                        disabled={saving}
                        onClick={onClose}
                        className="inline-flex h-10 items-center justify-center rounded-lg border border-gray-200 px-4 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:opacity-50 dark:border-white/20 dark:text-gray-200 dark:hover:bg-white/10"
                    >
                        {t('common.cancel')}
                    </button>
                    <button
                        type="button"
                        disabled={saving}
                        onClick={() => void handleSave()}
                        className="inline-flex h-10 items-center justify-center rounded-lg border border-gray-900 bg-gray-900 px-4 text-sm font-medium text-white transition-colors hover:bg-gray-800 disabled:opacity-50 dark:border-white dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100"
                    >
                        {saving ? t('familys.settings.saving') : t('familys.settings.save')}
                    </button>
                </div>
            </div>
        </div>
    )
}
