'use client';

/**
 * Page admin "/admin/media" — gestionnaire central des médias.
 *
 * Listing + filtres + upload + détails (visibilité, alt, caption) + suppression.
 * Tout est gardé dans un seul fichier pour rester lisible — la complexité
 * grandit-elle, on extraira un MediaDetailsDrawer dédié.
 */

import { registerPage } from '../../admin/registry.js';
import { useState, useEffect, useCallback, useRef } from 'react';
import { Card, Button, Modal, Input, Textarea, Select } from '@zen/core/shared/components';
import { useToast } from '@zen/core/toast';
import { CloudUploadIcon, Delete02Icon, Copy01Icon } from '@zen/core/shared/icons';
import AdminHeader from '../../admin/components/AdminHeader.js';
import MediaGrid from '../components/MediaGrid.client.js';
import MediaFilters from '../components/MediaFilters.client.js';
import MediaImage from '../components/MediaImage.client.js';

const MEDIA_API = '/zen/api/media';

const VISIBILITY_OPTIONS = [
  { value: 'private', label: 'Privé' },
  { value: 'public',  label: 'Public' },
];

function MediaDetails({ media, onClose, onUpdated, onDeleted, canDelete, canEdit }) {
  const toast = useToast();
  const [visibility, setVisibility] = useState(media.visibility);
  const [altText, setAltText]       = useState(media.alt_text || '');
  const [caption, setCaption]       = useState(media.caption || '');
  const [referenceCount, setReferenceCount] = useState(null);
  const [saving, setSaving]   = useState(false);
  const [deleting, setDeleting] = useState(false);

  useEffect(() => {
    let cancelled = false;
    fetch(`${MEDIA_API}/${media.id}`, { credentials: 'include' })
      .then(r => r.json())
      .then(data => { if (!cancelled) setReferenceCount(data.referenceCount ?? 0); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, [media.id]);

  const url = `/zen/api/media/file/${media.slug}`;
  const isImage = media.mime_type?.startsWith('image/');
  const fullUrl = typeof window !== 'undefined' ? `${window.location.origin}${url}` : url;

  const handleSave = async () => {
    setSaving(true);
    try {
      const response = await fetch(`${MEDIA_API}/${media.id}`, {
        method: 'PATCH',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ visibility, altText, caption }),
      });
      const data = await response.json();
      if (!response.ok) throw new Error(data.message || 'Échec de la mise à jour');
      toast.success('Média mis à jour');
      onUpdated?.(data.media);
    } catch (err) {
      toast.error(err.message);
    } finally {
      setSaving(false);
    }
  };

  const handleDelete = async () => {
    if (!confirm('Supprimer définitivement ce média ?')) return;
    setDeleting(true);
    try {
      const response = await fetch(`${MEDIA_API}/${media.id}`, {
        method: 'DELETE',
        credentials: 'include',
      });
      const data = await response.json();
      if (!response.ok) throw new Error(data.message || 'Échec de la suppression');
      toast.success('Média supprimé');
      onDeleted?.(media.id);
    } catch (err) {
      toast.error(err.message);
    } finally {
      setDeleting(false);
    }
  };

  const handleCopyUrl = async () => {
    try {
      await navigator.clipboard.writeText(fullUrl);
      toast.success('URL copiée');
    } catch {
      toast.error('Impossible de copier');
    }
  };

  return (
    <Modal
      isOpen={true}
      onClose={onClose}
      title={media.original_name}
      size="xl"
      footer={
        <div className="flex items-center justify-between">
          {canDelete ? (
            <Button variant="danger" icon={Delete02Icon} onClick={handleDelete} loading={deleting}>
              Supprimer
            </Button>
          ) : <div />}
          <div className="flex gap-2">
            <Button variant="ghost" onClick={onClose}>Fermer</Button>
            {canEdit && (
              <Button variant="primary" onClick={handleSave} loading={saving}>
                Enregistrer
              </Button>
            )}
          </div>
        </div>
      }
    >
      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        <div className="bg-neutral-50 dark:bg-neutral-950 rounded-lg overflow-hidden flex items-center justify-center min-h-64">
          {isImage ? (
            <MediaImage
              media={media}
              width={800}
              height={600}
              className="max-w-full max-h-96 w-auto h-auto object-contain"
              alt={altText || media.original_name}
            />
          ) : (
            <div className="text-center p-6 text-sm text-neutral-500">
              {media.mime_type}
              <br />
              <a href={url} target="_blank" rel="noreferrer" className="text-blue-500 hover:underline mt-2 inline-block">
                Ouvrir le fichier
              </a>
            </div>
          )}
        </div>

        <div className="space-y-3">
          <div>
            <label className="block text-xs font-medium text-neutral-700 dark:text-white mb-1">URL publique</label>
            <div className="flex gap-1">
              <Input value={fullUrl} onChange={() => {}} disabled />
              <Button variant="secondary" icon={Copy01Icon} onClick={handleCopyUrl} />
            </div>
            <p className="mt-1 text-[11px] text-neutral-500">
              {visibility === 'public' ? 'Accessible sans connexion.' : 'Privé : accessible uniquement aux utilisateurs avec la permission media.view.'}
            </p>
          </div>

          <Select
            label="Visibilité"
            value={visibility}
            onChange={setVisibility}
            options={VISIBILITY_OPTIONS}
            disabled={!canEdit}
            placeholder=""
          />

          {isImage && (
            <Input
              label="Texte alternatif"
              value={altText}
              onChange={setAltText}
              disabled={!canEdit}
              description="Décrit l'image pour les lecteurs d'écran et le SEO."
            />
          )}

          <Textarea
            label="Légende"
            value={caption}
            onChange={setCaption}
            disabled={!canEdit}
            rows={2}
          />

          <div className="text-xs text-neutral-500 dark:text-neutral-400 space-y-1 pt-2 border-t border-neutral-200 dark:border-neutral-800">
            <div>Type : <span className="text-neutral-700 dark:text-neutral-300">{media.mime_type}</span></div>
            <div>Taille : <span className="text-neutral-700 dark:text-neutral-300">{Math.round(Number(media.size_bytes) / 1024)} Ko</span></div>
            {referenceCount !== null && (
              <div>Utilisé par : <span className="text-neutral-700 dark:text-neutral-300">{referenceCount} contenu(s)</span></div>
            )}
          </div>
        </div>
      </div>
    </Modal>
  );
}

const MediaPage = ({ user }) => {
  const toast = useToast();
  const fileInputRef = useRef(null);
  const canUpload = user?.permissions?.includes('media.upload');
  const canDelete = user?.permissions?.includes('media.delete');

  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [uploading, setUploading] = useState(false);
  const [filters, setFilters] = useState({ search: '', kind: '', visibility: '' });
  const [selected, setSelected] = useState(null);

  const { error: toastError } = toast;
  const fetchItems = useCallback(async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({ limit: '60' });
      if (filters.search)     params.set('search', filters.search);
      if (filters.kind)       params.set('kind', filters.kind);
      if (filters.visibility) params.set('visibility', filters.visibility);

      const response = await fetch(`${MEDIA_API}?${params}`, { credentials: 'include' });
      if (!response.ok) throw new Error(`Error ${response.status}`);
      const data = await response.json();
      setItems(data.media || []);
    } catch (err) {
      toastError(err.message || 'Échec du chargement');
    } finally {
      setLoading(false);
    }
  }, [filters, toastError]);

  useEffect(() => {
    fetchItems();
  }, [fetchItems]);

  const handleUpload = async (event) => {
    const files = Array.from(event.target.files || []);
    if (files.length === 0) return;

    setUploading(true);
    try {
      for (const file of files) {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('visibility', 'private');

        const response = await fetch(MEDIA_API, {
          method: 'POST',
          credentials: 'include',
          body: formData,
        });
        const data = await response.json();
        if (!response.ok) {
          toast.error(`${file.name} : ${data.message || 'échec'}`);
        }
      }
      toast.success(`${files.length} fichier(s) téléversé(s)`);
      await fetchItems();
    } finally {
      setUploading(false);
      if (fileInputRef.current) fileInputRef.current.value = '';
    }
  };

  return (
    <div className="flex flex-col gap-4 sm:gap-6 lg:gap-8">
      <AdminHeader
        title="Médias"
        description="Bibliothèque de fichiers utilisés dans le contenu du site."
        action={canUpload && (
          <>
            <input
              ref={fileInputRef}
              type="file"
              multiple
              onChange={handleUpload}
              className="hidden"
            />
            <Button
              variant="primary"
              icon={CloudUploadIcon}
              onClick={() => fileInputRef.current?.click()}
              loading={uploading}
            >
              Téléverser
            </Button>
          </>
        )}
      />

      <MediaFilters filters={filters} onChange={setFilters} />

      <Card variant="default">
        <MediaGrid
          items={items}
          loading={loading}
          onSelect={(media) => setSelected(media)}
          emptyMessage={
            filters.search || filters.kind || filters.visibility
              ? 'Aucun média ne correspond aux filtres'
              : 'Aucun média téléversé pour le moment'
          }
        />
      </Card>

      {selected && (
        <MediaDetails
          media={selected}
          onClose={() => setSelected(null)}
          onUpdated={(updated) => {
            setItems(prev => prev.map(m => m.id === updated.id ? updated : m));
            setSelected(updated);
          }}
          onDeleted={(id) => {
            setItems(prev => prev.filter(m => m.id !== id));
            setSelected(null);
          }}
          canDelete={canDelete}
          canEdit={canUpload}
        />
      )}
    </div>
  );
};

export default MediaPage;

registerPage({ slug: 'media', title: 'Médias', Component: MediaPage });
