import React, { useState, useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { Eye, EyeOff, Loader2, Shield} from 'lucide-react'
import { useQuery } from '@tanstack/react-query'
import { useVaultContext } from '@/context/VaultProvider'
import { useCreateVault, useUpdateVault, useCreateEntry, useUpdateEntry, useCreateGrant, useMe } from '@/hooks/useVault'
import { vaultApi, type Vault, type VaultEntry } from '@/services/api'
import { SearchableMultiSelect } from './searchable-multi-select'
import { DateTimePicker } from './datetime-picker'

// ── Shared primitives (inline so no shadcn dep required) ─────────────────────

function cn(...classes: (string | undefined | false)[]) {
  return classes.filter(Boolean).join(' ')
}

function Overlay({ onClick }: { onClick: () => void }) {
  return (
    <div
      className='fixed inset-0 z-50 bg-black/25 backdrop-blur-sm'
      onClick={onClick}
    />
  )
}

function Modal({ children, className }: { children: React.ReactNode, className?: string }) {
  return (
    <div className={cn('fixed left-[50%] top-[50%] z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl border bg-background p-6 shadow-2xl animate-in fade-in zoom-in-95 duration-200', className)}>
      {children}
    </div>
  )
}

function ModalHeader({ title, description }: { title: string; description?: string }) {
  return (
    <div className='mb-5'>
      <h2 className='text-lg font-semibold'>{title}</h2>
      {description && <p className='text-muted-foreground mt-1 text-sm'>{description}</p>}
    </div>
  )
}

function Field({ label, error, children, icon: Icon }: { label: string; error?: string; children: React.ReactNode, icon?: any }) {
  return (
    <div className='space-y-1.5'>
      <div className='flex items-center gap-2'>
        {Icon && <Icon className='h-3.5 w-3.5 text-muted-foreground' />}
        <label className='text-sm font-medium'>{label}</label>
      </div>
      {children}
      {error && <p className='text-destructive text-xs'>{error}</p>}
    </div>
  )
}

function Inp(props: React.InputHTMLAttributes<HTMLInputElement>) {
  return (
    <input
      {...props}
      className={cn(
        'flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
        props.className
      )}
    />
  )
}

function Btn({
  children, variant = 'default', className, ...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> & { variant?: 'default' | 'outline' | 'ghost' }) {
  const base = 'inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-9 px-4 py-2'
  const variants = {
    default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
    outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
    ghost:   'hover:bg-accent hover:text-accent-foreground',
  }
  return (
    <button {...props} className={cn(base, variants[variant], className)}>
      {children}
    </button>
  )
}

function ModalFooter({ children, className }: { children: React.ReactNode, className?: string }) {
  return <div className={cn('mt-6 flex justify-end gap-2', className)}>{children}</div>
}

// ── VaultCreateDialog ─────────────────────────────────────────────────────────

const vaultSchema = z.object({ name: z.string().min(1, 'Name required').max(200) })
type VaultForm = z.infer<typeof vaultSchema>

export function VaultCreateDialog({ open, onOpenChange, editVault }: {
  open: boolean
  onOpenChange: (o: boolean) => void
  editVault?: Vault
}) {
  const createVault = useCreateVault()
  const updateVault = useUpdateVault()
  const { register, handleSubmit, reset, formState: { errors, isSubmitting } } = useForm<VaultForm>({
    resolver: zodResolver(vaultSchema),
    defaultValues: editVault ? { name: editVault.name } : { name: '' }
  })

  useEffect(() => {
    if (editVault) reset({ name: editVault.name })
    else reset({ name: '' })
  }, [editVault, reset])

  if (!open) return null

  const onSubmit = async (values: VaultForm) => {
    if (editVault) {
      await updateVault.mutateAsync({ id: editVault.id, name: values.name })
    } else {
      await createVault.mutateAsync(values.name)
    }
    reset()
    onOpenChange(false)
  }

  return (
    <>
      <Overlay onClick={() => onOpenChange(false)} />
      <Modal>
        <ModalHeader 
          title={editVault ? 'Edit Vault' : 'Create Vault'} 
          description={editVault ? 'Update the name of your vault.' : 'A vault holds your encrypted credentials.'} 
        />
        <form onSubmit={handleSubmit(onSubmit)} className='space-y-4'>
          <Field label='Vault Name' error={errors.name?.message}>
            <Inp placeholder='e.g. Production' {...register('name')} />
          </Field>
          <ModalFooter>
            <Btn variant='outline' type='button' onClick={() => { reset(); onOpenChange(false) }}>Cancel</Btn>
            <Btn type='submit' disabled={isSubmitting}>
              {isSubmitting && <Loader2 className='h-4 w-4 animate-spin' />}
              {editVault ? 'Save Changes' : 'Create'}
            </Btn>
          </ModalFooter>
        </form>
      </Modal>
    </>
  )
}

// ── EntryFormDialog ────────────────────────────────────────────────────────────

const entrySchema = z.object({
  domain:   z.string().max(253).optional().or(z.literal('')),
  username: z.string().optional().or(z.literal('')),
  password: z.string().optional().or(z.literal('')),
  alias:    z.string().max(200).optional().or(z.literal('')),
  notes:    z.string().optional().or(z.literal('')),
}).refine(data => {
  return data.domain?.trim() || data.username?.trim() || data.password?.trim()
}, {
  message: "At least one field (Domain, Username, or Password) must have a value",
  path: ["domain"] // We point to domain as a generic target for the error
})

type EntryForm = z.infer<typeof entrySchema>

export function EntryFormDialog({ open, onOpenChange, vaultId, editEntry }: {
  open: boolean
  onOpenChange: (o: boolean) => void
  vaultId: string
  editEntry?: VaultEntry
}) {
  const [showPw, setShowPw] = useState(false)
  const createEntry = useCreateEntry(vaultId)
  const updateEntry = useUpdateEntry(vaultId)

  const { register, handleSubmit, reset, formState: { errors, isSubmitting } } = useForm<EntryForm>({
    resolver: zodResolver(entrySchema),
    defaultValues: editEntry
      ? { alias: editEntry.alias, domain: editEntry.domain, username: editEntry.username, password: '', notes: editEntry.notes }
      : { alias: '', domain: '', username: '', password: '', notes: '' },
  })

  useEffect(() => {
    if (editEntry) {
      reset({ 
        alias: editEntry.alias || '', 
        domain: editEntry.domain || '',
        username: editEntry.username || '', 
        password: '', 
        notes: editEntry.notes || '' 
      })

      if (editEntry.has_password || editEntry.has_notes) {
        import('@/lib/crypto').then(async (crypto) => {
          try {
            const keyPair = await crypto.generateRSAKeyPair()
            const publicKey = await crypto.exportPublicKeyPEM(keyPair.publicKey)
            const creds = await vaultApi.getEntryCredentials(vaultId, editEntry.id, publicKey)
            
            let password = creds.password
            let notes = creds.notes
            if (creds.encryptedPayload) {
              const payloadStr = await crypto.decryptWithPrivateKey(keyPair.privateKey, creds.encryptedPayload)
              const payload = JSON.parse(payloadStr)
              password = payload.password
              notes = payload.notes
            }

            reset({
              alias: editEntry.alias || '', 
              domain: editEntry.domain || '',
              username: editEntry.username || '', 
              password: password || '', 
              notes: notes || '' 
            })
          } catch (e) {
            console.error("Failed to fetch credentials for edit", e)
          }
        })
      }
    } else {
      reset({ alias: '', domain: '', username: '', password: '', notes: '' })
    }
  }, [editEntry, reset, vaultId])

  if (!open) return null

  const onSubmit = async (values: EntryForm) => {
    if (editEntry) {
      await updateEntry.mutateAsync({ entryId: editEntry.id, data: values })
    } else {
      await createEntry.mutateAsync(values)
    }
    reset()
    onOpenChange(false)
  }

  return (
    <>
      <Overlay onClick={() => onOpenChange(false)} />
      <Modal>
        <ModalHeader
          title={editEntry ? 'Edit Credential' : 'New Credential'}
          description='Credentials are encrypted with AES-256-GCM before storage.'
        />
        <form onSubmit={handleSubmit(onSubmit)} className='space-y-4'>
          <Field label='Domain / URL' error={errors.domain?.message}>
            <Inp placeholder='e.g. amazon.com' {...register('domain')} />
          </Field>
          
          <Field label='Username / Email' error={errors.username?.message}>
            <Inp placeholder='admin@example.com' {...register('username')} />
          </Field>

          <Field label='Password' error={errors.password?.message}>
            <div className='relative'>
              <Inp
                type={showPw ? 'text' : 'password'}
                placeholder='••••••••••'
                className='pr-12'
                {...register('password')}
              />

              <button
                type='button'
                onClick={() => setShowPw(!showPw)}
                className='absolute inset-y-0 right-1 flex items-center pr-4 text-muted-foreground hover:text-foreground'
              >
                {showPw ? (
                  <EyeOff className='h-4 w-4' />
                ) : (
                  <Eye className='h-4 w-4' />
                )}
              </button>
            </div>
          </Field>

          <Field label='Alias / Label' error={errors.alias?.message}>
            <Inp placeholder='e.g. Work Admin' {...register('alias')} />
          </Field>

          <Field label='Notes (optional)'>
            <textarea
              rows={2}
              placeholder='Any additional notes...'
              className='flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring resize-none'
              {...register('notes')}
            />
          </Field>
          
          <ModalFooter>
            <Btn variant='outline' type='button' onClick={() => { reset(); onOpenChange(false) }}>Cancel</Btn>
            <Btn type='submit' disabled={isSubmitting}>
              {isSubmitting && <Loader2 className='h-4 w-4 animate-spin' />}
              {editEntry ? 'Save Changes' : 'Create'}
            </Btn>
          </ModalFooter>
        </form>
      </Modal>
    </>
  )
}

// ── GrantAccessDialog ─────────────────────────────────────────────────────────

const EXPIRY_OPTIONS = [
  { label: 'Custom', value: 'custom' },
  { label: 'No expiry', value: null  },
  { label: '1 hour',    value: '1h'  },
  { label: '8 hours',  value: '8h'  },
  { label: '24 hours', value: '24h' },
  { label: '7 days',   value: '7d'  },
  { label: '30 days',  value: '30d' }
] as const

export function GrantAccessDialog({ open, onOpenChange, scope, scopeId, scopeLabel }: {
  open: boolean
  onOpenChange: (o: boolean) => void
  scope: 'vault' | 'entry'
  scopeId: string
  scopeLabel?: string
}) {
  const { getUsers } = useVaultContext()
  const { data: me } = useMe()
  const createGrant = useCreateGrant()
  const [selectedIds, setSelectedIds] = useState<string[]>([])
  const [expiresIn, setExpiresIn] = useState<string | null>('custom')
  const [customDate, setCustomDate] = useState<Date | undefined>(undefined)

  const { data: users = [] } = useQuery({
    queryKey: ['vault-grant-users'],
    queryFn: getUsers,
    enabled: open,
  })

  const otherUsers = users.filter(u => u.id !== me?.id)

  const fetchUsers = async (search: string, page: number) => {
    const filtered = otherUsers.filter(
      (u) =>
        u.full_name?.toLowerCase().includes(search.toLowerCase()) ||
        u.email?.toLowerCase().includes(search.toLowerCase())
    )
    const pageSize = 20
    const start = (page - 1) * pageSize
    const end = start + pageSize
    return {
      data: filtered.slice(start, end),
      hasMore: end < filtered.length
    }
  }

  if (!open) return null

  const handleGrant = async () => {
    if (selectedIds.length === 0) return
    const expiry = expiresIn === 'custom' && customDate ? customDate.toISOString() : expiresIn
    
    await Promise.all(selectedIds.map(id => 
      createGrant.mutateAsync({ 
        scope, 
        scope_id: scopeId, 
        grantee_id: id, 
        expires_in: expiry as any 
      })
    ))

    onOpenChange(false)
    setSelectedIds([])
    setExpiresIn('24h')
    setCustomDate(undefined)
  }

  return (
    <>
      <Overlay onClick={() => onOpenChange(false)} />
      <Modal className='max-w-md'>
        <ModalHeader
          title='Grant Access'
          description={`Provide access to ${scope}${scopeLabel ? ` "${scopeLabel}"` : ''}. Specify the time period if needed.`}
        />

        <div className='space-y-6 py-2'>
          <div className='space-y-3'>
            <label className='text-sm font-medium text-foreground flex items-center gap-2'>
              Assigned Users
            </label>
            <SearchableMultiSelect 
              value={selectedIds}
              onChange={setSelectedIds}
              fetchData={fetchUsers}
              fieldMapping={{ value: 'id', label: 'full_name' }}
              placeholder='Search and select users...'
            />
          </div>

          <div className='space-y-4'>
            <label className='text-sm font-medium  text-foreground flex items-center gap-2'>
              Expiration Period
            </label>
            
            {expiresIn === 'custom' && (
              <div className='pt-2 animate-in slide-in-from-top-2 duration-200'>
                <DateTimePicker 
                  value={customDate}
                  onChange={setCustomDate}
                  minDate={new Date()}
                />
                <p className='text-[10px] text-muted-foreground mt-2 px-1 flex items-center gap-1.5'>
                   <Shield className='h-3 w-3' /> Selected access will expire at the specified time.
                </p>
              </div>
            )}
            <div className='grid grid-cols-3 gap-2'>
              {EXPIRY_OPTIONS.map((opt) => (
                <button
                  key={String(opt.value)}
                  onClick={() => setExpiresIn(opt.value as any)}
                  className={cn(
                    'px-2 py-2 rounded text-xs font-medium border transition-all active:scale-95',
                    expiresIn === opt.value
                       ? 'bg-primary text-primary-foreground border-primary shadow-lg shadow-primary/20'
                       : 'bg-card border-muted-foreground/10 hover:border-primary/50 hover:bg-card/5'
                  )}
                >
                  {opt.label}
                </button>
              ))}
            </div>
          </div>
        </div>

        <ModalFooter className='mt-8 pt-6 border-t'>
          <Btn variant='outline' className='rounded h-10 px-4' onClick={() => onOpenChange(false)}>Cancel</Btn>
          <Btn 
            onClick={handleGrant} 
            disabled={selectedIds.length === 0 || createGrant.isPending || (expiresIn === 'custom' && !customDate)}
            className='rounded h-10 px-4 shadow-xl shadow-primary/20 bg-primary font-bold'
          >
            {createGrant.isPending && <Loader2 className='mr-2 h-4 w-4 animate-spin' />}
            Grant Access
          </Btn>
        </ModalFooter>
      </Modal>
    </>
  )
}

export function ConfirmDialog({
  open,
  onOpenChange,
  title,
  description,
  confirmText = 'Confirm',
  cancelText = 'Cancel',
  onConfirm,
  variant = 'destructive',
  loading = false,
}: {
  open: boolean
  onOpenChange: (o: boolean) => void
  title: string
  description: string
  confirmText?: string
  cancelText?: string
  onConfirm: () => void
  variant?: 'default' | 'destructive'
  loading?: boolean
}) {
  if (!open) return null

  return (
    <>
      <Overlay onClick={() => onOpenChange(false)} />
      <Modal className='max-w-sm'>
        <ModalHeader title={title} description={description} />
        <ModalFooter>
          <Btn variant='outline' onClick={() => onOpenChange(false)} disabled={loading}>
            {cancelText}
          </Btn>
          <Btn 
            variant={variant === 'destructive' ? 'default' : 'default'}
            className={variant === 'destructive' ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90' : ''}
            onClick={() => {
              onConfirm()
            }}
            disabled={loading}
          >
            {loading && <Loader2 className='h-4 w-4 animate-spin' />}
            {confirmText}
          </Btn>
        </ModalFooter>
      </Modal>
    </>
  )
}
 