"use client";

import {
  DragEvent,
  PointerEvent as ReactPointerEvent,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import {
  deleteProjectPhoto,
  getProjectDefaultAvatars,
  setProjectDefaultAvatar,
  uploadProjectPhoto,
} from "@/lib/projects-client";
import { getApiUrl } from "@/lib/auth";
import type { ProjectSummary } from "@/types/projects";
import styles from "@/app/profile/page.module.css";

/* ------------------------------------------------------------------ */
/*  Constants                                                          */
/* ------------------------------------------------------------------ */

const PASTEL_COLORS = [
  "#F9D5E5",
  "#D5EAF7",
  "#D5F5E3",
  "#FFF3CD",
  "#E8D5F5",
  "#FFE0CC",
];

const CIRCLE_SIZE = 200;
const MIN_SCALE = 0.5;
const MAX_SCALE = 3;

/* ------------------------------------------------------------------ */
/*  Props                                                              */
/* ------------------------------------------------------------------ */

type Props = {
  project: ProjectSummary;
  onSuccess: (updated: ProjectSummary) => void;
  onClose: () => void;
};

/* ------------------------------------------------------------------ */
/*  Component                                                          */
/* ------------------------------------------------------------------ */

export function ProjectPhotoModal({ project, onSuccess, onClose }: Props) {
  const apiUrl = getApiUrl();

  const [modalTab, setModalTab] = useState<"upload" | "defaults">("upload");
  const [modalMessage, setModalMessage] = useState("");
  const [loading, setLoading] = useState(false);

  /* upload / crop */
  const [file, setFile] = useState<File | null>(null);
  const [imageSrc, setImageSrc] = useState<string | null>(null);
  const [imgNaturalSize, setImgNaturalSize] = useState<{ w: number; h: number } | null>(null);
  const [baseScale, setBaseScale] = useState(1);
  const [crop, setCrop] = useState({ x: 0, y: 0, scale: 1 });
  const [dragging, setDragging] = useState(false);
  const [bgColor, setBgColor] = useState<string>(project.projectBgColor ?? PASTEL_COLORS[0]);
  const [showCustomPicker, setShowCustomPicker] = useState(false);

  const fileInputRef = useRef<HTMLInputElement>(null);
  const cropPreviewRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const dragStartRef = useRef<{ px: number; py: number; cx: number; cy: number } | null>(null);

  /* default avatars */
  const [defaultAvatars, setDefaultAvatars] = useState<string[]>([]);
  const [selectedDefault, setSelectedDefault] = useState<string | null>(null);

  useEffect(() => {
    getProjectDefaultAvatars(project.id)
      .then((data) => { if (Array.isArray(data)) setDefaultAvatars(data); })
      .catch(() => {});
  }, [project.id]);

  /* ---------------------------------------------------------------- */
  /*  File picking                                                     */
  /* ---------------------------------------------------------------- */

  const pickFile = (picked: File) => {
    setFile(picked);
    const src = URL.createObjectURL(picked);
    setImageSrc(src);
    setCrop({ x: 0, y: 0, scale: 1 });
    setImgNaturalSize(null);
    setBaseScale(1);
    setSelectedDefault(null);
    setModalTab("upload");
  };

  const onDragOver = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); setDragging(true); };
  const onDragLeave = () => setDragging(false);
  const onDrop = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault(); setDragging(false);
    const dropped = e.dataTransfer.files[0];
    if (dropped) pickFile(dropped);
  };
  const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const picked = e.target.files?.[0]; if (picked) pickFile(picked);
  };

  /* ---------------------------------------------------------------- */
  /*  Crop drag                                                        */
  /* ---------------------------------------------------------------- */

  const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {
    if (!imageSrc) return;
    e.preventDefault();
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
    dragStartRef.current = { px: e.clientX, py: e.clientY, cx: crop.x, cy: crop.y };
  };

  const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {
    if (!dragStartRef.current) return;
    const { px, py, cx, cy } = dragStartRef.current;
    setCrop((prev) => ({ ...prev, x: cx + (e.clientX - px), y: cy + (e.clientY - py) }));
  };

  const onPointerUp = () => { dragStartRef.current = null; };

  const onWheel = (e: React.WheelEvent<HTMLDivElement>) => {
    e.stopPropagation();
    setCrop((prev) => {
      const delta = e.deltaY > 0 ? -0.05 : 0.05;
      return { ...prev, scale: Math.min(MAX_SCALE, Math.max(MIN_SCALE, prev.scale + delta)) };
    });
  };

  /* ---------------------------------------------------------------- */
  /*  Render cropped image to blob                                     */
  /* ---------------------------------------------------------------- */

  const renderCroppedBlob = useCallback((): Promise<Blob | null> => {
    return new Promise((resolve) => {
      if (!imageSrc || !imgNaturalSize) { resolve(null); return; }
      const img = new window.Image();
      img.onload = () => {
        const canvas = canvasRef.current;
        if (!canvas) { resolve(null); return; }
        const size = 400;
        canvas.width = size;
        canvas.height = size;
        const ctx = canvas.getContext("2d");
        if (!ctx) { resolve(null); return; }

        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, size, size);

        ctx.beginPath();
        ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
        ctx.clip();

        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, size, size);

        const ratio = size / CIRCLE_SIZE;
        const scaledW = imgNaturalSize.w * baseScale * crop.scale * ratio;
        const scaledH = imgNaturalSize.h * baseScale * crop.scale * ratio;
        const dx = (size - scaledW) / 2 + crop.x * ratio;
        const dy = (size - scaledH) / 2 + crop.y * ratio;

        ctx.drawImage(img, dx, dy, scaledW, scaledH);
        canvas.toBlob((blob) => resolve(blob), "image/png");
      };
      img.src = imageSrc;
    });
  }, [imageSrc, imgNaturalSize, bgColor, baseScale, crop]);

  /* ---------------------------------------------------------------- */
  /*  Actions                                                          */
  /* ---------------------------------------------------------------- */

  const onUploadPhoto = async () => {
    setLoading(true); setModalMessage("");
    try {
      const blob = await renderCroppedBlob();
      if (!blob) { setModalMessage("Erreur de recadrage."); return; }
      const updated = await uploadProjectPhoto(project.id, blob, bgColor);
      onSuccess(updated);
      onClose();
    } catch (err) {
      setModalMessage(err instanceof Error ? err.message : "Erreur réseau");
    } finally { setLoading(false); }
  };

  const onSelectDefaultAvatar = async () => {
    if (!selectedDefault) return;
    setLoading(true); setModalMessage("");
    try {
      const updated = await setProjectDefaultAvatar(project.id, selectedDefault, bgColor);
      onSuccess(updated);
      onClose();
    } catch (err) {
      setModalMessage(err instanceof Error ? err.message : "Erreur réseau");
    } finally { setLoading(false); }
  };

  const onDeletePhoto = async () => {
    setLoading(true); setModalMessage("");
    try {
      const updated = await deleteProjectPhoto(project.id);
      onSuccess(updated);
    } catch (err) {
      setModalMessage(err instanceof Error ? err.message : "Erreur réseau");
    } finally { setLoading(false); }
  };

  /* ---------------------------------------------------------------- */
  /*  Derived                                                          */
  /* ---------------------------------------------------------------- */

  const hasCurrentPhoto = !!project.projectImageUrl;
  const currentImageSrc = project.projectImageUrl ? `${apiUrl}${project.projectImageUrl}` : null;
  const canSave = modalTab === "upload" ? !!imageSrc : !!selectedDefault;

  /* ---------------------------------------------------------------- */
  /*  Render                                                           */
  /* ---------------------------------------------------------------- */

  return (
    <div className={styles.modalBackdrop} onClick={onClose}>
      <div className={styles.modal} onClick={(e) => e.stopPropagation()}>
        <canvas ref={canvasRef} style={{ display: "none" }} />

        {/* header */}
        <div className={styles.modalHeader}>
          <h2>Photo du projet</h2>
          <button type="button" className={styles.modalClose} onClick={onClose} aria-label="Fermer">✕</button>
        </div>

        {/* tabs */}
        <div className={styles.tabs}>
          <button
            type="button"
            className={`${styles.tab} ${modalTab === "upload" ? styles.tabActive : ""}`}
            onClick={() => setModalTab("upload")}
          >
            Ma photo
          </button>
          {defaultAvatars.length > 0 && (
            <button
              type="button"
              className={`${styles.tab} ${modalTab === "defaults" ? styles.tabActive : ""}`}
              onClick={() => setModalTab("defaults")}
            >
              Avatars
            </button>
          )}
        </div>

        {/* ----- tab: upload ----- */}
        {modalTab === "upload" && (
          <>
            {imageSrc ? (
              <>
                <div className={styles.cropContainer}>
                  <div
                    ref={cropPreviewRef}
                    className={styles.cropCircle}
                    style={{ width: CIRCLE_SIZE, height: CIRCLE_SIZE, background: bgColor }}
                    onPointerDown={onPointerDown}
                    onPointerMove={onPointerMove}
                    onPointerUp={onPointerUp}
                    onWheel={onWheel}
                  >
                    <img
                      src={imageSrc}
                      alt=""
                      className={styles.cropImg}
                      draggable={false}
                      onLoad={(e) => {
                        const el = e.currentTarget;
                        const bs = Math.max(CIRCLE_SIZE / el.naturalWidth, CIRCLE_SIZE / el.naturalHeight);
                        setBaseScale(bs);
                        setImgNaturalSize({ w: el.naturalWidth, h: el.naturalHeight });
                      }}
                      style={imgNaturalSize ? {
                        width: imgNaturalSize.w * baseScale,
                        height: imgNaturalSize.h * baseScale,
                        marginLeft: -(imgNaturalSize.w * baseScale) / 2,
                        marginTop: -(imgNaturalSize.h * baseScale) / 2,
                        transform: `translate(${crop.x}px, ${crop.y}px) scale(${crop.scale})`,
                      } : { display: "none" }}
                    />
                  </div>
                </div>

                <div className={styles.zoomRow}>
                  <span className={styles.zoomLabel}>−</span>
                  <input
                    type="range"
                    min={MIN_SCALE * 100}
                    max={MAX_SCALE * 100}
                    value={crop.scale * 100}
                    className={styles.zoomSlider}
                    onChange={(e) => setCrop((prev) => ({ ...prev, scale: Number(e.target.value) / 100 }))}
                  />
                  <span className={styles.zoomLabel}>+</span>
                </div>

                <button type="button" className={styles.changeFile} onClick={() => fileInputRef.current?.click()}>
                  Changer l&apos;image
                </button>
              </>
            ) : hasCurrentPhoto ? (
              <div className={styles.currentPhotoSection}>
                <div className={styles.currentPhotoCircle} style={{ background: project.projectBgColor ?? undefined }}>
                  <img src={currentImageSrc!} alt="Photo actuelle" />
                </div>
                <p className={styles.currentPhotoHint}>Photo actuelle</p>
                <div className={styles.currentPhotoActions}>
                  <button type="button" className={styles.changeFile} onClick={() => fileInputRef.current?.click()}>
                    Changer la photo
                  </button>
                  <button
                    type="button"
                    className={styles.deletePhotoBtn}
                    onClick={onDeletePhoto}
                    disabled={loading}
                  >
                    {loading ? "Suppression…" : "Supprimer la photo"}
                  </button>
                </div>
              </div>
            ) : (
              <div
                className={`${styles.dropZone} ${dragging ? styles.dropZoneActive : ""}`}
                onDragOver={onDragOver}
                onDragLeave={onDragLeave}
                onDrop={onDrop}
                onClick={() => fileInputRef.current?.click()}
              >
                <svg className={styles.dropIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                  <polyline points="17 8 12 3 7 8" />
                  <line x1="12" y1="3" x2="12" y2="15" />
                </svg>
                <p className={styles.dropText}>Glisse une image ici</p>
                <p className={styles.dropSub}>ou clique pour parcourir · PNG, JPG, WEBP</p>
              </div>
            )}

            <input
              ref={fileInputRef}
              type="file"
              accept="image/png,image/jpeg,image/jpg,image/webp"
              className={styles.hiddenInput}
              onChange={onFileInputChange}
            />
          </>
        )}

        {/* ----- tab: defaults ----- */}
        {modalTab === "defaults" && (
          <div className={styles.defaultGrid}>
            {defaultAvatars.map((url) => (
              <button
                key={url}
                type="button"
                className={`${styles.defaultItem} ${selectedDefault === url ? styles.defaultItemActive : ""}`}
                style={{ background: bgColor }}
                onClick={() => { setSelectedDefault(url); setFile(null); setImageSrc(null); }}
              >
                <img src={`${apiUrl}${url}`} alt="" />
              </button>
            ))}
          </div>
        )}

        {/* color picker (masqué si photo existante sans nouvelle sélection) */}
        {(imageSrc || selectedDefault || !project.projectImageUrl) && (
          <div className={styles.colorSection}>
            <span className={styles.colorLabel}>Couleur de fond</span>
            <div className={styles.colorRow}>
              {PASTEL_COLORS.map((c) => (
                <button
                  key={c}
                  type="button"
                  className={`${styles.colorDot} ${bgColor === c ? styles.colorDotActive : ""}`}
                  style={{ background: c }}
                  onClick={() => setBgColor(c)}
                />
              ))}
              <button
                type="button"
                className={`${styles.colorDot} ${styles.colorCustom} ${!PASTEL_COLORS.includes(bgColor) ? styles.colorDotActive : ""}`}
                style={!PASTEL_COLORS.includes(bgColor) ? { background: bgColor } : undefined}
                onClick={() => setShowCustomPicker((v) => !v)}
              >
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <circle cx="12" cy="12" r="10" /><path d="M2 12h20" />
                </svg>
              </button>
            </div>
            {showCustomPicker && (
              <input
                type="color"
                className={styles.nativeColorPicker}
                value={bgColor}
                onChange={(e) => setBgColor(e.target.value)}
              />
            )}
          </div>
        )}

        {modalMessage && <p className={styles.modalError}>{modalMessage}</p>}

        {/* actions */}
        {canSave && (
          <div className={styles.modalActions}>
            <button type="button" className="btn btn-soft" onClick={onClose} disabled={loading}>
              Annuler
            </button>
            <button
              type="button"
              className="btn btn-primary"
              onClick={modalTab === "upload" ? onUploadPhoto : onSelectDefaultAvatar}
              disabled={loading}
            >
              {loading ? "Enregistrement…" : "Enregistrer"}
            </button>
          </div>
        )}
      </div>
    </div>
  );
}
