import React, { useEffect, useMemo, useRef, useState } from 'react'
import {
  Alert,
  Box,
  FormControl,
  InputLabel,
  Grid,
  Typography,
  List,
  ListItem,
  ListItemText,
  Button,
  IconButton,
  TextField,
  Switch,
  FormControlLabel,
  Chip,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  MenuItem,
  Select
} from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import DeleteIcon from '@mui/icons-material/Delete'
import PlayArrowIcon from '@mui/icons-material/PlayArrow'
import EditIcon from '@mui/icons-material/Edit'
import AddIcon from '@mui/icons-material/Add'
import CloudDownloadIcon from '@mui/icons-material/CloudDownload'
import type { Server } from '../context/ServersContext'
import { useServers } from '../context/ServersContext'
import { buildLibraryCacheKey, getLibraryCacheStats, pruneLibraryCache } from '../libraryCache'
import { syncLibraryCache } from '../librarySync'
const DEFAULT_SERVER_FORM = { name: '', host: '', port: undefined, apiKey: '', ssl: false, forceApiKeyInQuery: false }

type SettingsPageProps = {
  onClose?: () => void
  devOverlayEnabled: boolean
  onDevOverlayEnabledChange: (enabled: boolean) => void
  libraryDisplayMode: 'grid' | 'table'
  onLibraryDisplayModeChange: (mode: 'grid' | 'table') => void
}

export default function SettingsPage({ onClose, devOverlayEnabled, onDevOverlayEnabledChange, libraryDisplayMode, onLibraryDisplayModeChange }: SettingsPageProps) {
  const { servers, addServer, updateServer, removeServer, testServerById, testServerConfig, setActiveServerId, activeServerId } = useServers()
  const [editing, setEditing] = useState<Server | null>(null)
  const [form, setForm] = useState<Omit<Server, 'id' | 'lastTest'>>(DEFAULT_SERVER_FORM)
  const [testing, setTesting] = useState(false)
  const [syncingServerId, setSyncingServerId] = useState<string | null>(null)
  const [lastTest, setLastTest] = useState<string | null>(null)
  const [detailsOpen, setDetailsOpen] = useState(false)
  const [detailsText, setDetailsText] = useState<string | null>(null)
  const [draftLibraryDisplayMode, setDraftLibraryDisplayMode] = useState<'grid' | 'table'>(libraryDisplayMode)
  const [draftDevOverlayEnabled, setDraftDevOverlayEnabled] = useState(devOverlayEnabled)
  const [syncCompletionNotices, setSyncCompletionNotices] = useState<Record<string, string>>({})
  const [cacheStorageText, setCacheStorageText] = useState('0 B')
  const [cacheTrackCount, setCacheTrackCount] = useState(0)
  const [cacheSearchCount, setCacheSearchCount] = useState(0)
  const [cacheSnapshotCount, setCacheSnapshotCount] = useState(0)
  const [cacheUpdatedAt, setCacheUpdatedAt] = useState<number | null>(null)
  const syncNoticeTimeoutsRef = useRef<Record<string, number>>({})
  const currentCacheKey = useMemo(() => buildLibraryCacheKey(servers), [servers])

  useEffect(() => {
    setEditing(null)
    setForm(DEFAULT_SERVER_FORM)
    setLastTest(null)
    setDetailsText(null)
    setDetailsOpen(false)
  }, [])

  useEffect(() => {
    setDraftLibraryDisplayMode(libraryDisplayMode)
  }, [libraryDisplayMode])

  useEffect(() => {
    setDraftDevOverlayEnabled(devOverlayEnabled)
  }, [devOverlayEnabled])

  useEffect(() => {
    return () => {
      Object.values(syncNoticeTimeoutsRef.current).forEach((timeoutId) => window.clearTimeout(timeoutId))
    }
  }, [])

  const preferencesDirty = draftLibraryDisplayMode !== libraryDisplayMode || draftDevOverlayEnabled !== devOverlayEnabled

  const formatBytes = (value: number) => {
    if (!value || value <= 0) return '0 B'
    const units = ['B', 'KB', 'MB', 'GB']
    let size = value
    let unitIndex = 0

    while (size >= 1024 && unitIndex < units.length - 1) {
      size /= 1024
      unitIndex += 1
    }

    return `${size >= 10 || unitIndex === 0 ? size.toFixed(0) : size.toFixed(1)} ${units[unitIndex]}`
  }

  const refreshCacheStats = async (cacheKey: string) => {
    if (!cacheKey) {
      setCacheStorageText('0 B')
      setCacheTrackCount(0)
      setCacheSearchCount(0)
      setCacheSnapshotCount(0)
      setCacheUpdatedAt(null)
      return
    }

    await pruneLibraryCache(cacheKey)
    const stats = await getLibraryCacheStats(cacheKey)
    setCacheStorageText(formatBytes(stats.activeBytes))
    setCacheTrackCount(stats.trackCount)
    setCacheSearchCount(stats.searchEntryCount)
    setCacheSnapshotCount(stats.snapshotCount)
    setCacheUpdatedAt(stats.updatedAt)
  }

  const startAdd = () => {
    setEditing(null)
    setForm(DEFAULT_SERVER_FORM)
  }

  const startEdit = (s: Server) => {
    setEditing(s)
    setForm({ name: s.name || '', host: s.host, port: s.port, apiKey: s.apiKey || '', ssl: !!s.ssl, forceApiKeyInQuery: !!s.forceApiKeyInQuery })
    setLastTest(s.lastTest ? `${s.lastTest.message} (${new Date(s.lastTest.timestamp).toLocaleString()})` : null)
  }

  const handleSave = () => {
    if (editing) {
      updateServer(editing.id, form)
    } else {
      const srv = addServer(form)
      setActiveServerId(srv.id)
    }
    onClose && onClose()
  }

  const handleDelete = (s: Server) => {
    if (confirm(`Delete server ${s.name || s.host}?`)) {
      removeServer(s.id)
    }
  }

  const handleTestExisting = async (s: Server) => {
    setTesting(true)
    try {
      const res = await testServerById(s.id)
      setLastTest(`${res.message}`)
    } catch (e: any) {
      setLastTest(`Error: ${e?.message ?? String(e)}`)
    } finally {
      setTesting(false)
    }
  }

  const handleTestForm = async () => {
    setTesting(true)
    try {
      const res = await testServerConfig(form)
      setLastTest(`${res.message}`)
    } catch (e: any) {
      setLastTest(`Error: ${e?.message ?? String(e)}`)
    } finally {
      setTesting(false)
    }
  }

  const handleSyncServer = async (server: Server) => {
    setSyncingServerId(server.id)

    try {
      const result = await syncLibraryCache(servers, { targetServerIds: [server.id] })
      const summary = result.summaries[server.id]
      if (!summary) throw new Error('Sync did not return a server summary')

      updateServer(server.id, { syncSummary: summary })

      if (summary.message) {
        setLastTest(summary.message)
        await refreshCacheStats(result.cacheKey)
        return
      }

      const addedCount = result.addedCounts[server.id] ?? 0
      const removedCount = result.removedCounts[server.id] ?? 0
      const completionMessage = addedCount === 0 && removedCount === 0
        ? `Sync complete. No file changes. ${summary.total} cached items.`
        : `Sync complete. Added ${addedCount} files, removed ${removedCount} files.`
      setLastTest(`Sync complete. ${summary.total} cached items.`)
      setSyncCompletionNotices((current) => ({ ...current, [server.id]: completionMessage }))
      await refreshCacheStats(result.cacheKey)
      if (syncNoticeTimeoutsRef.current[server.id]) {
        window.clearTimeout(syncNoticeTimeoutsRef.current[server.id])
      }
      syncNoticeTimeoutsRef.current[server.id] = window.setTimeout(() => {
        setSyncCompletionNotices((current) => {
          const next = { ...current }
          delete next[server.id]
          return next
        })
        delete syncNoticeTimeoutsRef.current[server.id]
      }, 8000)
    } catch (error: any) {
      const message = error?.message ?? String(error)
      updateServer(server.id, {
        syncSummary: {
          updatedAt: Date.now(),
          total: 0,
          counts: {},
          message: `Sync failed: ${message}`,
        },
      })
      setLastTest(`Sync failed: ${message}`)
    } finally {
      setSyncingServerId(null)
    }
  }

  useEffect(() => {
    void refreshCacheStats(currentCacheKey)
  }, [currentCacheKey])

  const handleSavePreferences = () => {
    if (draftLibraryDisplayMode !== libraryDisplayMode) {
      onLibraryDisplayModeChange(draftLibraryDisplayMode)
    }

    if (draftDevOverlayEnabled !== devOverlayEnabled) {
      onDevOverlayEnabledChange(draftDevOverlayEnabled)
    }
  }

  return (
    <Box sx={{ p: { xs: 1, sm: 2, lg: 3 }, minHeight: '100%', bgcolor: 'background.default' }}>
      <Box sx={{ width: '100%', maxWidth: 1280, mx: 'auto' }}>
        <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 3 }}>
          <Box sx={{ display: 'flex', alignItems: 'center' }}>
            <IconButton onClick={() => onClose && onClose()} aria-label="back" size="large" sx={{ mr: 1 }}>
              <ArrowBackIcon />
            </IconButton>
            <Typography variant="h6">Hydrus Servers</Typography>
          </Box>
        </Box>

        <Box sx={{ border: '1px solid rgba(255,255,255,0.08)', borderRadius: 2, bgcolor: 'background.paper', p: { xs: 1.5, sm: 2 }, mb: { xs: 2, lg: 3 } }}>
          <Box sx={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 2, mb: 1.5, flexWrap: 'wrap' }}>
            <Box>
              <Typography variant="subtitle1" sx={{ mb: 0.5 }}>Interface preferences</Typography>
              <Typography variant="body2" color="text.secondary">
                Save Library layout and development UI changes together.
              </Typography>
            </Box>
            <Button variant="contained" onClick={handleSavePreferences} disabled={!preferencesDirty}>
              Save preferences
            </Button>
          </Box>

          <FormControl size="small" sx={{ minWidth: 180, maxWidth: 240, mb: import.meta.env.DEV ? 2 : 0 }}>
            <InputLabel id="settings-library-display-mode-label">Display</InputLabel>
            <Select
              labelId="settings-library-display-mode-label"
              value={draftLibraryDisplayMode}
              label="Display"
              onChange={(event) => setDraftLibraryDisplayMode(event.target.value as 'grid' | 'table')}
            >
              <MenuItem value="grid">Grid</MenuItem>
              <MenuItem value="table">Table</MenuItem>
            </Select>
          </FormControl>

          {import.meta.env.DEV && (
            <>
              <Typography variant="subtitle1" sx={{ mb: 0.5 }}>Developer tools</Typography>
              <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
                Control development-only UI that can get in the way on smaller screens.
              </Typography>
              <FormControlLabel
                control={<Switch checked={draftDevOverlayEnabled} onChange={(event) => setDraftDevOverlayEnabled(event.target.checked)} />}
                label={draftDevOverlayEnabled ? 'Floating dev overlay enabled' : 'Floating dev overlay disabled'}
                sx={{ alignItems: 'flex-start', m: 0 }}
              />
            </>
          )}
        </Box>

        <Box sx={{ border: '1px solid rgba(255,255,255,0.08)', borderRadius: 2, bgcolor: 'background.paper', p: { xs: 1.5, sm: 2 }, mb: { xs: 2, lg: 3 } }}>
          <Typography variant="subtitle1" sx={{ mb: 0.5 }}>Library cache</Typography>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
            The app keeps one active IndexedDB snapshot and automatically removes older sync cache snapshots.
          </Typography>
          <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
            <Chip label={`Storage: ${cacheStorageText}`} size="small" color="primary" variant="outlined" />
            <Chip label={`Tracks: ${cacheTrackCount}`} size="small" variant="outlined" />
            <Chip label={`Searches: ${cacheSearchCount}`} size="small" variant="outlined" />
            <Chip label={`Snapshots kept: ${cacheSnapshotCount}`} size="small" variant="outlined" />
          </Box>
          <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}>
            {cacheUpdatedAt ? `Cache updated: ${new Date(cacheUpdatedAt).toLocaleString()}` : 'Cache has not been written yet.'}
          </Typography>
        </Box>

        <Grid container spacing={{ xs: 2, lg: 3 }} alignItems="flex-start">
          <Grid item xs={12} lg={5}>
            <Box sx={{ border: '1px solid rgba(255,255,255,0.08)', borderRadius: 2, bgcolor: 'background.paper', p: { xs: 1.5, sm: 2 } }}>
              <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
                <Typography variant="subtitle1">Configured servers</Typography>
                <Button startIcon={<AddIcon />} onClick={startAdd} size="large" className="touch-target">
                  Add
                </Button>
              </Box>

              <List>
                {servers.length === 0 && <Typography color="text.secondary">No servers configured yet</Typography>}
                {servers.map((s) => (
                  <ListItem key={s.id} sx={{ flexWrap: 'wrap', alignItems: 'flex-start', px: 0, py: 1.25, borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
                    <ListItemText primary={s.name || s.host} secondary={s.host} sx={{ mr: 2 }} />
                    <Box sx={{ display: 'flex', gap: 1, mt: { xs: 1, md: 0 }, flexWrap: 'wrap', width: { xs: '100%', md: 'auto' } }}>
                      <Button size="large" onClick={() => setActiveServerId(s.id)} className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                        {s.id === activeServerId ? 'Active' : 'Set active'}
                      </Button>
                      <Button variant="outlined" size="large" onClick={() => handleTestExisting(s)} startIcon={<PlayArrowIcon />} className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                        Test
                      </Button>
                      <Button variant="outlined" size="large" onClick={() => handleSyncServer(s)} startIcon={<CloudDownloadIcon />} disabled={syncingServerId === s.id} className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                        {syncingServerId === s.id ? 'Syncing...' : typeof s.syncSummary?.total === 'number' ? `Sync cache (${s.syncSummary.total})` : 'Sync cache'}
                      </Button>
                      <IconButton size="large" aria-label="edit" onClick={() => startEdit(s)}>
                        <EditIcon />
                      </IconButton>
                      <IconButton size="large" aria-label="delete" onClick={() => handleDelete(s)}>
                        <DeleteIcon />
                      </IconButton>
                    </Box>
                    <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap', width: '100%', mt: 1 }}>
                      {s.lastTest && s.lastTest.message && <Chip label={s.lastTest.message} size="small" />}
                      {typeof s.syncSummary?.total === 'number' && <Chip label={`Cached: ${s.syncSummary.total} items`} size="small" color="primary" variant="outlined" />}
                      {s.syncSummary?.message && <Chip label={s.syncSummary.message} size="small" color="error" variant="outlined" />}
                      {s.syncSummary?.counts && Object.entries(s.syncSummary.counts).map(([section, count]) => (
                        <Chip key={`${s.id}-${section}`} label={`${section}: ${count}`} size="small" variant="outlined" />
                      ))}
                      {s.forceApiKeyInQuery && <Chip label="API key in query" size="small" />}
                    </Box>
                    {syncCompletionNotices[s.id] && (
                      <Alert severity="success" sx={{ width: '100%', mt: 1, py: 0 }}>
                        {syncCompletionNotices[s.id]}
                      </Alert>
                    )}
                    {s.syncSummary?.updatedAt && (
                      <Typography variant="caption" color="text.secondary" sx={{ width: '100%', mt: 1 }}>
                        Last sync: {new Date(s.syncSummary.updatedAt).toLocaleString()}
                      </Typography>
                    )}
                  </ListItem>
                ))}
              </List>
            </Box>
          </Grid>

          <Grid item xs={12} lg={7}>
            <Box sx={{ border: '1px solid rgba(255,255,255,0.08)', borderRadius: 2, bgcolor: 'background.paper', p: { xs: 1.5, sm: 2 } }}>
              <Typography variant="subtitle1">{editing ? 'Edit server' : 'Add new server'}</Typography>
              <Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
                <TextField label="Name (optional)" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} fullWidth />
                <TextField label="Host (IP or host, e.g. 192.168.1.128)" value={form.host} onChange={(e) => setForm({ ...form, host: e.target.value })} fullWidth />
                <TextField label="Port (optional)" value={form.port as any ?? ''} onChange={(e) => setForm({ ...form, port: e.target.value })} fullWidth />
                <TextField label="API Key (optional)" value={form.apiKey} onChange={(e) => setForm({ ...form, apiKey: e.target.value })} fullWidth />
                <FormControlLabel control={<Switch checked={!!form.ssl} onChange={(e) => setForm({ ...form, ssl: e.target.checked })} />} label="Use HTTPS (SSL)" />
                <FormControlLabel control={<Switch checked={!!form.forceApiKeyInQuery} onChange={(e) => setForm({ ...form, forceApiKeyInQuery: e.target.checked })} />} label="Send API key in query parameter" />

                <Box sx={{ display: 'flex', gap: 1, mt: 1, flexWrap: 'wrap' }}>
                  <Button variant="contained" onClick={handleSave} disabled={!form.host} size="large" className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                    Save
                  </Button>
                  <Button variant="outlined" onClick={handleTestForm} disabled={!form.host || testing} startIcon={<PlayArrowIcon />} size="large" className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                    {testing ? 'Testing...' : 'Test connection'}
                  </Button>
                  <Button onClick={() => { setEditing(null); setForm(DEFAULT_SERVER_FORM); setLastTest(null) }} size="large" className="touch-target" sx={{ flexGrow: { xs: 1, sm: 0 } }}>
                    Reset
                  </Button>
                </Box>

                {lastTest && (
                  <Box sx={{ mt: 1 }}>
                    <Typography variant="caption">Last test: {lastTest}</Typography>
                    <Box sx={{ mt: 1 }}>
                      <Button size="small" onClick={() => {
                        const obj = editing?.lastTest ?? servers.find((s) => s.id === editing?.id)?.lastTest ?? null
                        setDetailsText(obj ? JSON.stringify(obj, null, 2) : lastTest)
                        setDetailsOpen(true)
                      }}>Show details</Button>
                    </Box>
                  </Box>
                )}

                <Dialog open={detailsOpen} onClose={() => setDetailsOpen(false)} fullWidth maxWidth="md">
                  <DialogTitle>Connection details</DialogTitle>
                  <DialogContent>
                    <Box component="pre" sx={{ whiteSpace: 'pre-wrap', fontFamily: 'monospace', fontSize: 12 }}>{detailsText}</Box>
                  </DialogContent>
                  <DialogActions>
                    <Button onClick={() => setDetailsOpen(false)}>Close</Button>
                  </DialogActions>
                </Dialog>
                </Box>
            </Box>
          </Grid>
        </Grid>
      </Box>
    </Box>
  )
}
