// WeddingGallery.tsx
import React, { JSX, useCallback, useEffect, useState } from 'react';
import {
  AppBar,
  Alert,
  Box,
  Button,
  Card,
  CardContent,
  CardMedia,
  Chip,
  CircularProgress,
  Container,
  CssBaseline,
  Grid,
  IconButton,
  LinearProgress,
  Paper,
  Snackbar,
  TextField,
  ThemeProvider,
  Toolbar,
  Typography,
  createTheme,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
} from '@mui/material';
import {
  CameraAlt,
  CloudUpload,
  Delete as DeleteIcon,
  Download,
  Replay,
  Favorite,
} from '@mui/icons-material';
import { useDropzone } from 'react-dropzone';
import LightboxModal from './LightboxModal';

type WeddingPhoto = {
  id: number | string;
  url: string;
  title?: string;
  filename?: string;
  created_at?: string;
  date?: string;
  path?: string;
};

type FileQueueItem = {
  id: string;
  file: File;
  previewUrl: string;
  progress: number;
  status: 'pending' | 'uploading' | 'done' | 'error';
  error?: string;
  uploadedPhoto?: WeddingPhoto;
};

type FolderInfo = {
  title: string;
  count: number;
  thumb?: string;
};

/* ============================
   Config
   ============================ */
const MFS_API_BASE = 'https://mfs-api.midastix.com';
const MAX_FILE_SIZE = 10 * 1024 * 1024;
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
const MAX_QUEUE_FILES = 30;

/* ============================
   Helpers / API functions
   ============================ */
const toAbsoluteUrl = (path?: string) => {
  if (!path) return '';
  if (path.startsWith('http://') || path.startsWith('https://')) return path;
  return `${MFS_API_BASE}${path}`;
};

const uploadFileXHR = (
  file: File,
  onProgress: (pct: number) => void,
  title?: string
): Promise<{ success: boolean; data?: any; error?: string }> =>
  new Promise((resolve) => {
    try {
      const xhr = new XMLHttpRequest();
      const url = `${MFS_API_BASE}/image-upload/single`;
      xhr.open('POST', url, true);
      xhr.setRequestHeader('Accept', 'application/json');

      xhr.upload.onprogress = (ev) => {
        if (!ev.lengthComputable) return;
        const pct = Math.round((ev.loaded / ev.total) * 100);
        onProgress(pct);
      };

      xhr.onload = () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          try {
            const json = JSON.parse(xhr.responseText);
            resolve({ success: true, data: json });
          } catch (e) {
            resolve({ success: true, data: xhr.responseText });
          }
        } else {
          const txt = xhr.responseText || `HTTP ${xhr.status}`;
          resolve({ success: false, error: txt });
        }
      };

      xhr.onerror = () => resolve({ success: false, error: 'Network error' });

      const fd = new FormData();
      fd.append('file', file, file.name);
      if (title) fd.append('title', title);

      xhr.send(fd);
    } catch (err: any) {
      resolve({ success: false, error: err?.message ?? String(err) });
    }
  });

const fetchImagesApi = async (title = ''): Promise<WeddingPhoto[]> => {
  const url =
    title && title.trim() !== '' ? `${MFS_API_BASE}/image-upload?title=${encodeURIComponent(title)}` : `${MFS_API_BASE}/image-upload`;
  const res = await fetch(url, { headers: { accept: 'application/json' } });
  if (!res.ok) {
    const txt = await res.text();
    throw new Error(txt || `HTTP ${res.status}`);
  }
  const body = await res.json();
  let imagesArray: any[] = [];
  if (Array.isArray(body)) imagesArray = body;
  else if (Array.isArray(body.images)) imagesArray = body.images;
  else if (body.data && Array.isArray(body.data.images)) imagesArray = body.data.images;
  else {
    const firstArray = Object.values(body).find((v) => Array.isArray(v));
    if (Array.isArray(firstArray)) imagesArray = firstArray as any[];
  }
  return imagesArray.map((it: any) => ({
    id: it.id ?? it._id ?? `${it.filename ?? Math.random()}`,
    url: toAbsoluteUrl(it.path ?? it.url),
    title: it.title ?? it.filename ?? '',
    filename: it.filename,
    created_at: it.created_at ?? it.createdAt,
    date: it.date,
    path: it.path,
  }));
};

const deletePhotoApi = async (id: number | string) => {
  const url = `${MFS_API_BASE}/image-upload/${id}`;
  const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
  const txt = await res.text();
  if (!res.ok) throw new Error(txt || `HTTP ${res.status}`);
  return txt || 'deleted';
};

const deleteFolderApi = async (title: string) => {
  const url = `${MFS_API_BASE}/image-upload/folder?title=${encodeURIComponent(title)}`;
  const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
  const txt = await res.text();
  if (!res.ok) throw new Error(txt || `HTTP ${res.status}`);
  return txt || 'folder deleted';
};

/* ============================
   Theme & SafeGrid
   ============================ */
const theme = createTheme({
  palette: {
    primary: { main: '#0f766e', light: '#2dd4bf' },
    secondary: { main: '#d4af37' },
    background: { default: '#fbfdfb' },
  },
  typography: { fontFamily: '"Inter", "Roboto", sans-serif' },
});

const SafeGrid = Grid as any;

/* ============================
   Component
   ============================ */
export default function WeddingGallery(): JSX.Element {
  const [photosAll, setPhotosAll] = useState<WeddingPhoto[]>([]);
  const [folders, setFolders] = useState<FolderInfo[]>([]);
  const [folderOpenTitle, setFolderOpenTitle] = useState<string | null>(null);
  const [folderPhotos, setFolderPhotos] = useState<WeddingPhoto[]>([]);
  const [folderModalOpen, setFolderModalOpen] = useState(false);

  const [queue, setQueue] = useState<FileQueueItem[]>([]);
  const [commonTitle, setCommonTitle] = useState<string>('');
  const [snackbar, setSnackbar] = useState<{ open: boolean; severity?: 'success' | 'error' | 'info'; message: string }>({
    open: false,
    severity: 'info',
    message: '',
  });

  const [deletingId, setDeletingId] = useState<number | string | null>(null);
  const [deletingFolder, setDeletingFolder] = useState<string | null>(null);

  // lightbox state
  const [lightboxOpen, setLightboxOpen] = useState(false);
  const [lightboxStartIndex, setLightboxStartIndex] = useState(0);

  const loadAll = useCallback(async () => {
    try {
      const items = await fetchImagesApi('');
      setPhotosAll(items);
      const map = new Map<string, FolderInfo>();
      items.forEach((it) => {
        const title = it.title ?? 'untitled';
        if (!map.has(title)) map.set(title, { title, count: 0, thumb: it.url });
        const entry = map.get(title)!;
        entry.count += 1;
        if (!entry.thumb) entry.thumb = it.url;
      });
      setFolders(Array.from(map.values()).sort((a, b) => b.count - a.count));
    } catch (err: any) {
      console.error('loadAll error', err);
      setFolders([]);
      setSnackbar({ open: true, severity: 'error', message: `Failed to load: ${err?.message || err}` });
    }
  }, []);

  useEffect(() => {
    loadAll();
    return () => {
      queue.forEach((q) => {
        try {
          URL.revokeObjectURL(q.previewUrl);
        } catch { }
      });
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /* ============================
     Drop — enforce MAX_QUEUE_FILES
  ============================ */
  const onDrop = useCallback((acceptedFiles: File[]) => {
    if (!acceptedFiles || acceptedFiles.length === 0) return;

    const currentCount = queue.length;
    const available = Math.max(0, MAX_QUEUE_FILES - currentCount);

    if (available <= 0) {
      setSnackbar({ open: true, severity: 'error', message: `Queue full — maximum ${MAX_QUEUE_FILES} files allowed.` });
      return;
    }

    const acceptedToAdd = acceptedFiles.slice(0, available);
    const rejectedCount = acceptedFiles.length - acceptedToAdd.length;

    const now = Date.now();
    const items: FileQueueItem[] = acceptedToAdd.map((f, i) => {
      const id = `${now}-${currentCount + i}-${f.name}`;
      const tooLarge = f.size > MAX_FILE_SIZE;
      const invalidType = ALLOWED_TYPES.length > 0 && !ALLOWED_TYPES.includes(f.type);
      return {
        id,
        file: f,
        previewUrl: URL.createObjectURL(f),
        progress: 0,
        status: tooLarge || invalidType ? 'error' : 'pending',
        error: tooLarge ? `File too large ${(f.size / (1024 * 1024)).toFixed(1)}MB` : invalidType ? 'Invalid type' : undefined,
      } as FileQueueItem;
    });

    setQueue((prev) => [...items, ...prev]);

    if (rejectedCount > 0) {
      setSnackbar({
        open: true,
        severity: 'info',
        message: `Accepted ${acceptedToAdd.length} file(s). Rejected ${rejectedCount} file(s) due to the ${MAX_QUEUE_FILES}-file limit.`,
      });
    } else {
      setSnackbar({ open: true, severity: 'success', message: `Added ${acceptedToAdd.length} file(s) to the queue.` });
    }
  }, [queue.length]);

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    multiple: true,
    maxSize: MAX_FILE_SIZE,
    accept: ALLOWED_TYPES.length ? ALLOWED_TYPES.reduce((acc, t) => ({ ...acc, [t]: [] }), {} as any) : undefined,
  });

  /* ============================
     Upload logic
  ============================ */
  const uploadSingle = useCallback(
    async (item: FileQueueItem) => {
      setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'uploading', progress: 0, error: undefined } : q)));
      const res = await uploadFileXHR(item.file, (pct) => {
        setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, progress: pct } : q)));
      }, commonTitle || undefined);

      if (res.success) {
        const it = res.data;
        const uploadedPhoto: WeddingPhoto = {
          id: it.id ?? it._id,
          url: toAbsoluteUrl(it.path ?? it.url),
          title: it.title ?? it.filename ?? commonTitle ?? '',
          filename: it.filename,
          created_at: it.created_at ?? it.createdAt,
          path: it.path,
        };
        setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'done', progress: 100, uploadedPhoto } : q)));
        setPhotosAll((prev) => [uploadedPhoto, ...prev]);
        await loadAll();
        return true;
      } else {
        setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'error', error: res.error } : q)));
        console.error('upload failed', res.error);
        return false;
      }
    },
    [commonTitle, loadAll]
  );

  const uploadAll = useCallback(async () => {
    const pending = queue.filter((q) => q.status === 'pending' || q.status === 'error');
    if (!pending.length) {
      setSnackbar({ open: true, severity: 'info', message: 'No files to upload' });
      return;
    }
    for (const item of pending) {
      // eslint-disable-next-line no-await-in-loop
      await uploadSingle(item);
    }
    setSnackbar({ open: true, severity: 'success', message: 'Uploads complete' });
    setQueue((prev) => prev.filter((q) => q.status !== 'done'));
  }, [queue, uploadSingle]);

  const retryOne = (id: string) => {
    const item = queue.find((q) => q.id === id);
    if (item) uploadSingle(item);
  };

  const removeOne = (id: string) => {
    const item = queue.find((q) => q.id === id);
    if (item) {
      try {
        URL.revokeObjectURL(item.previewUrl);
      } catch { }
    }
    setQueue((prev) => prev.filter((q) => q.id !== id));
  };

  /* ============================
     Folder / modal management + lightbox hookup
  ============================ */
  const openFolder = async (title: string) => {
    setFolderOpenTitle(title);
    try {
      const items = await fetchImagesApi(title);
      setFolderPhotos(items);
      setFolderModalOpen(true);
    } catch (err: any) {
      console.error('openFolder error', err);
      setSnackbar({ open: true, severity: 'error', message: `Failed to load folder: ${err?.message || err}` });
    }
  };

  const handleDeletePhoto = async (id: number | string) => {
    if (!confirm('Delete this photo? This action cannot be undone.')) return;
    setDeletingId(id);
    try {
      await deletePhotoApi(id);
      setFolderPhotos((prev) => prev.filter((p) => p.id !== id));
      setPhotosAll((prev) => prev.filter((p) => p.id !== id));
      setSnackbar({ open: true, severity: 'success', message: 'Photo deleted' });
      await loadAll();
    } catch (err: any) {
      console.error('deletePhoto error', err);
      setSnackbar({ open: true, severity: 'error', message: `Failed to delete: ${err?.message || err}` });
    } finally {
      setDeletingId(null);
    }
  };

  const handleDeleteFolder = async (title: string) => {
    if (!confirm(`Delete entire folder "${title}" and all its photos? This is irreversible.`)) return;
    setDeletingFolder(title);
    try {
      await deleteFolderApi(title);
      setSnackbar({ open: true, severity: 'success', message: `Folder "${title}" deleted` });
      await loadAll();
      setFolderModalOpen(false);
    } catch (err: any) {
      console.error('deleteFolder error', err);
      setSnackbar({ open: true, severity: 'error', message: `Failed to delete folder: ${err?.message || err}` });
    } finally {
      setDeletingFolder(null);
    }
  };

  useEffect(() => {
    const map = new Map<string, FolderInfo>();
    photosAll.forEach((it) => {
      const title = it.title ?? 'untitled';
      if (!map.has(title)) map.set(title, { title, count: 0, thumb: it.url });
      const e = map.get(title)!;
      e.count += 1;
      if (!e.thumb) e.thumb = it.url;
    });
    setFolders(Array.from(map.values()).sort((a, b) => b.count - a.count));
  }, [photosAll]);

  /* ============================
     UI
  ============================ */
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <AppBar position="static" sx={{ bgcolor: 'primary.main' }}>
        <Toolbar>
          <CameraAlt sx={{ mr: 2 }} />
          <Typography variant="h6" sx={{ flexGrow: 1 }}>
            Wedding Gallery — Folders
          </Typography>
          <Chip icon={<Favorite />} label="Events" sx={{ bgcolor: 'secondary.main', color: '#111' }} />
        </Toolbar>
      </AppBar>

      <Container maxWidth="lg" sx={{ py: 4 }}>
        <Box textAlign="center" mb={3}>
          <Typography variant="h4">Events (Folders)</Typography>
          <Typography variant="body2" color="text.secondary">
            Only folders are shown here. Click a folder to manage photos inside.
          </Typography>
          <Typography variant="caption" color="text.secondary">
            Queue: {queue.length}/{MAX_QUEUE_FILES}
          </Typography>
        </Box>

        <Paper sx={{ p: 3, mb: 3 }}>
          <SafeGrid container spacing={2} alignItems="center">
            <SafeGrid item xs={12} md={8}>
              <Box
                {...getRootProps()}
                sx={{
                  p: 3,
                  border: '2px dashed',
                  borderColor: isDragActive ? 'primary.light' : 'grey.300',
                  borderRadius: 1,
                  textAlign: 'center',
                  cursor: 'pointer',
                }}
              >
                <input {...getInputProps()} />
                <CloudUpload sx={{ fontSize: 40, color: 'primary.main' }} />
                <Typography variant="h6">{isDragActive ? 'Drop images here' : 'Drag & drop images here, or click to select'}</Typography>
                <Typography variant="body2" color="text.secondary">
                  Max {(MAX_FILE_SIZE / (1024 * 1024)).toFixed(0)}MB per file. Allowed: jpg, png, gif, webp. Max {MAX_QUEUE_FILES} files in queue.
                </Typography>
              </Box>
            </SafeGrid>

            <SafeGrid item xs={12} md={4}>
              <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                <TextField size="small" placeholder="Event title (folder)" value={commonTitle} onChange={(e) => setCommonTitle(e.target.value)} />
                <Box sx={{ display: 'flex', gap: 1 }}>
                  <Button variant="contained" onClick={uploadAll} disabled={!queue.some((q) => q.status === 'pending' || q.status === 'error')} sx={{ bgcolor: 'primary.main' }}>
                    Upload All ({queue.filter((q) => q.status === 'pending' || q.status === 'error').length})
                  </Button>
                  <Button variant="outlined" onClick={() => { queue.forEach((q) => { try { URL.revokeObjectURL(q.previewUrl); } catch { } }); setQueue([]); setSnackbar({ open: true, severity: 'info', message: 'Cleared queue' }); }}>
                    Clear
                  </Button>
                </Box>

                {/* Queue preview thumbnails */}
                <Box sx={{ display: 'flex', gap: 1, mt: 1, overflowX: 'auto', py: 1 }}>
                  {queue.map((q) => (
                    <Card key={q.id} sx={{ width: 140, flex: '0 0 140px' }}>
                      <CardMedia component="img" height={90} image={q.previewUrl} sx={{ objectFit: 'cover' }} />
                      <CardContent sx={{ p: 1 }}>
                        <Typography variant="caption" noWrap>{q.file.name}</Typography>
                        <Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mt: 1 }}>
                          {q.status === 'uploading' ? <CircularProgress size={18} /> : q.status === 'done' ? <Typography variant="caption" color="success.main">Done</Typography> : q.status === 'error' ? <Typography variant="caption" color="error.main">Err</Typography> : <Typography variant="caption">Pending</Typography>}
                          <IconButton size="small" onClick={() => retryOne(q.id)} disabled={q.status !== 'error'}><Replay fontSize="small" /></IconButton>
                          <IconButton size="small" onClick={() => removeOne(q.id)}><DeleteIcon fontSize="small" /></IconButton>
                        </Box>
                        <LinearProgress variant="determinate" value={q.progress} sx={{ mt: 1 }} />
                      </CardContent>
                    </Card>
                  ))}
                </Box>
              </Box>
            </SafeGrid>
          </SafeGrid>
        </Paper>

        {/* Folders */}
        <Box sx={{ mb: 4 }}>
          {folders.length === 0 ? (
            <Paper sx={{ p: 6, textAlign: 'center' }}>
              <Typography variant="h6" color="text.secondary">No events found</Typography>
              <Typography variant="body2" color="text.secondary">Upload photos to create events (folders)</Typography>
            </Paper>
          ) : (
            <SafeGrid container spacing={3}>
              {folders.map((f) => (
                <SafeGrid item xs={12} sm={6} md={4} key={f.title}>
                  <Card sx={{ cursor: 'pointer', transition: 'transform .15s', '&:hover': { transform: 'translateY(-6px)' } }}>
                    <Box onClick={() => openFolder(f.title)}>
                      <Box sx={{ height: 200, overflow: 'hidden' }}>
                        <CardMedia component="img" image={f.thumb ?? ''} alt={f.title} sx={{ width: '100%', height: 200, objectFit: 'cover', backgroundColor: '#f4f6f7' }} />
                      </Box>
                      <CardContent>
                        <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                          <Box sx={{ minWidth: 0 }}>
                            <Typography variant="subtitle1" noWrap>{f.title}</Typography>
                            <Typography variant="caption" color="text.secondary">{f.count} photos</Typography>
                          </Box>
                          <Box>
                            <IconButton edge="end" size="small" onClick={async (e) => { e.stopPropagation(); await handleDeleteFolder(f.title); }}>
                              <DeleteIcon />
                            </IconButton>
                          </Box>
                        </Box>
                      </CardContent>
                    </Box>
                  </Card>
                </SafeGrid>
              ))}
            </SafeGrid>
          )}
        </Box>
      </Container>

      {/* Folder modal */}
      <Dialog open={folderModalOpen} onClose={() => setFolderModalOpen(false)} fullWidth maxWidth="md">
        <DialogTitle>
          Manage — {folderOpenTitle} ({folderPhotos.length})
          <Box component="span" sx={{ float: 'right' }}>
            <Button variant="outlined" color="error" size="small" onClick={() => { if (folderOpenTitle) handleDeleteFolder(folderOpenTitle); }} disabled={!!deletingFolder}>
              Delete Folder
            </Button>
          </Box>
        </DialogTitle>
        <DialogContent dividers>
          {folderPhotos.length === 0 ? (
            <Typography variant="body2">No photos in this event.</Typography>
          ) : (
            <Grid container spacing={2}>
              {folderPhotos.map((p, idx) => (
                <Grid key={p.id}>
                  <Card>
                    <Box sx={{ position: 'relative' }}>
                      {/* clicking image opens lightbox at that index */}
                      <Box
                        sx={{ cursor: 'pointer' }}
                        onClick={() => {
                          setLightboxStartIndex(idx);
                          setLightboxOpen(true);
                        }}
                      >
                        <CardMedia component="img" height="140" image={p.url} />
                      </Box>

                      <IconButton
                        sx={{ position: 'absolute', top: 6, right: 6, bgcolor: 'rgba(255,255,255,0.8)' }}
                        onClick={() => handleDeletePhoto(p.id)}
                        disabled={deletingId === p.id}
                      >
                        <DeleteIcon fontSize="small" />
                      </IconButton>
                    </Box>
                    <Box sx={{ p: 1 }}>
                      <Typography variant="caption" noWrap>{p.filename ?? p.title}</Typography>
                      <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mt: 1 }}>
                        <IconButton size="small" onClick={() => {
                          try {
                            const a = document.createElement('a');
                            a.href = p.url;
                            a.download = `${p.filename ?? p.title ?? 'photo'}.jpg`;
                            document.body.appendChild(a);
                            a.click();
                            a.remove();
                          } catch (err) {
                            console.error('download error', err);
                            setSnackbar({ open: true, severity: 'error', message: 'Download failed' });
                          }
                        }}>
                          <Download fontSize="small" />
                        </IconButton>
                        <Typography variant="caption" color="text.secondary">{p.created_at ? new Date(p.created_at).toLocaleDateString() : ''}</Typography>
                      </Box>
                    </Box>
                  </Card>
                </Grid>
              ))}
            </Grid>
          )}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setFolderModalOpen(false)}>Close</Button>
        </DialogActions>
      </Dialog>

      {/* Lightbox */}
      <LightboxModal
        open={lightboxOpen}
        photos={folderPhotos}
        startIndex={lightboxStartIndex}
        onClose={() => setLightboxOpen(false)}
      />

      <Snackbar open={snackbar.open} autoHideDuration={4000} onClose={() => setSnackbar((s) => ({ ...s, open: false }))}>
        <Alert severity={snackbar.severity || 'info'} onClose={() => setSnackbar((s) => ({ ...s, open: false }))}>
          {snackbar.message}
        </Alert>
      </Snackbar>
    </ThemeProvider>
  );
}
