// screens-projects.jsx

function NewProjectModal({ onClose, onCreated }) {
  const [name, setName] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const create = () => {
    if (!name.trim()) { setErr('Name is required'); return; }
    setSaving(true); setErr(null);
    window.ZAMPP_API.fetch('/projects', { method: 'POST', body: JSON.stringify({ name: name.trim() }) })
      .then(p => { onCreated(p); onClose(); })
      .catch(e => { setSaving(false); setErr(e.message || 'Failed to create project'); });
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ width: 420 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ fontSize: 15, fontWeight: 600 }}>New project</div>
          <button className="icon-btn" aria-label="Close" onClick={onClose}><Icon name="x" /></button>
        </div>
        <div className="modal-body">
          <div className="field">
            <label className="field-label">Project name</label>
            <input className="field-input" value={name} onChange={e => setName(e.target.value)}
              placeholder="e.g. Sunday Night Game" autoFocus
              onKeyDown={e => e.key === 'Enter' && !saving && create()} />
          </div>
          {err && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 4 }}>{err}</div>}
        </div>
        <div className="modal-foot">
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <span style={{ flex: 1 }} />
          <button className="btn primary" onClick={create} disabled={saving}>
            {saving ? 'Creating…' : 'Create project'}
          </button>
        </div>
      </div>
    </div>
  );
}

function Projects({ onOpenProject, navigate }) {
  const [projects, setProjects] = React.useState(window.ZAMPP_DATA?.PROJECTS || []);
  const ASSETS = window.ZAMPP_DATA?.ASSETS || [];
  const [search, setSearch] = React.useState('');
  const [view, setView] = React.useState('grid');
  const [showNew, setShowNew] = React.useState(false);
  const [menuFor, setMenuFor] = React.useState(null);
  const [renamingProject, setRenamingProject] = React.useState(null);
  const [confirm, confirmModal] = window.useConfirm();
  const [accessProject, setAccessProject] = React.useState(null);
  const isAdmin = window.ZAMPP_DATA?.ME?.role === 'admin';
  const manageAccess = (p) => { setMenuFor(null); setAccessProject(p); };

  const refresh = React.useCallback(() => {
    window.ZAMPP_API.fetch('/projects')
      .then(list => {
        const updated = (list || []).map((p, i) => ({
          ...p,
          color: (window.ZAMPP_DATA.PROJECTS.find(x => x.id === p.id) || {}).color
                 || (window.PROJECT_COLORS ? window.PROJECT_COLORS[p.id.charCodeAt(p.id.length - 1) % window.PROJECT_COLORS.length] : null)
                 || 'var(--accent)',
          assets: (ASSETS || []).filter(a => a.project_id === p.id).length,
          updated: window.ZAMPP_API.fmtRelative(p.updated_at),
        }));
        window.ZAMPP_DATA.PROJECTS = updated;
        setProjects(updated);
      })
      .catch(() => {});
  }, [ASSETS]);

  const onCreated = (p) => { refresh(); };

  const renameProject = (p) => { setMenuFor(null); setRenamingProject(p); };

  const deleteProject = async (p) => {
    setMenuFor(null);
    if (!(await confirm({ title: 'Delete project?', message: 'Delete project "' + p.name + '"?\nThis fails if there are still assets attached.' }))) return;
    window.ZAMPP_API.fetch('/projects/' + p.id, { method: 'DELETE' })
      .then(refresh)
      .catch(e => alert('Delete failed: ' + e.message));
  };

  React.useEffect(() => {
    if (!menuFor) return;
    const close = () => setMenuFor(null);
    window.addEventListener('click', close);
    return () => window.removeEventListener('click', close);
  }, [menuFor]);

  let filtered = projects;
  if (search) filtered = filtered.filter(p => p.name.toLowerCase().includes(search.toLowerCase()));

  return (
    <div className="page">
      {confirmModal}
      <div className="page-header">
        <h1>Projects</h1>
        <span className="subtitle">{filtered.length} projects</span>
        <div className="spacer" />
        <div className="search" style={{ width: 240 }}>
          <Icon name="search" className="search-icon" />
          <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search projects…" />
        </div>
        <div className="tab-group">
          <button className={view === 'grid' ? 'active' : ''} onClick={() => setView('grid')} aria-label="Grid view" title="Grid view"><Icon name="grid" size={12} /></button>
          <button className={view === 'list' ? 'active' : ''} onClick={() => setView('list')} aria-label="List view" title="List view"><Icon name="list" size={12} /></button>
        </div>
        <button className="btn primary" onClick={() => setShowNew(true)}><Icon name="plus" />New project</button>
      </div>
      <div className="page-body">
        {filtered.length === 0 ? (
          <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>
            {search ? 'No matching projects.' : 'No projects yet.'}
            {!search && (
              <div style={{ marginTop: 12 }}>
                <button className="btn primary" onClick={() => setShowNew(true)}><Icon name="plus" />New project</button>
              </div>
            )}
          </div>
        ) : view === 'grid' ? (
          <div className="projects-grid">
            {filtered.map(p => (
              <ProjectCard
                key={p.id}
                project={p}
                assets={ASSETS}
                canManageAccess={isAdmin}
                onOpen={() => onOpenProject(p)}
                onRename={() => renameProject(p)}
                onManageAccess={() => manageAccess(p)}
                onDelete={() => deleteProject(p)}
              />
            ))}
          </div>
        ) : (
          <div className="panel">
            <div className="list-row head" style={{ padding: '12px 16px', gridTemplateColumns: '1fr 100px 120px 120px 80px' }}>
              <div>Project</div><div>Assets</div><div>Storage</div><div>Updated</div><div></div>
            </div>
            {filtered.map(p => (
              <div key={p.id} className="list-row" style={{ padding: '12px 16px', gridTemplateColumns: '1fr 100px 120px 120px 80px', borderBottom: '1px solid var(--border)', cursor: 'pointer' }} onClick={() => onOpenProject(p)}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <div style={{ width: 8, height: 32, borderRadius: 2, background: p.color || 'var(--accent)' }} />
                  <div>{p.name}</div>
                </div>
                <div className="col-sub">{p.assets || 0}</div>
                <div className="col-sub">·</div>
                <div className="col-sub">{p.updated || '·'}</div>
                <div style={{ position: 'relative' }} onClick={e => e.stopPropagation()}>
                  <button className="icon-btn" aria-label="Project actions" onClick={e => { e.stopPropagation(); setMenuFor(menuFor === p.id ? null : p.id); }}><Icon name="more" /></button>
                  {menuFor === p.id && (
                    <div className="row-menu" onClick={e => e.stopPropagation()}>
                      <button onClick={() => { setMenuFor(null); onOpenProject(p); }}><Icon name="library" size={11} />Open</button>
                      <button onClick={() => renameProject(p)}><Icon name="edit" size={11} />Rename…</button>
                      {isAdmin && <button onClick={() => manageAccess(p)}><Icon name="users" size={11} />Manage access…</button>}
                      <button className="danger" onClick={() => deleteProject(p)}><Icon name="trash" size={11} />Delete</button>
                    </div>
                  )}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
      {showNew && <NewProjectModal onClose={() => setShowNew(false)} onCreated={onCreated} />}
      {renamingProject && (
        <RenameProjectModal
          project={renamingProject}
          onClose={() => setRenamingProject(null)}
          onSaved={() => { setRenamingProject(null); refresh(); }}
        />
      )}
      {accessProject && (
        <ProjectAccessModal
          project={accessProject}
          onClose={() => setAccessProject(null)}
        />
      )}
    </div>
  );
}

// Admin-only: grant/revoke per-project access to users and groups.
// Backed by GET/POST/DELETE /api/v1/projects/:id/access.
function ProjectAccessModal({ project, onClose }) {
  const [grants, setGrants]   = React.useState([]);
  const [users, setUsers]     = React.useState([]);
  const [groups, setGroups]   = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [err, setErr]         = React.useState(null);

  // Add-grant form state.
  const [subjType, setSubjType] = React.useState('user');
  const [subjId, setSubjId]     = React.useState('');
  const [level, setLevel]       = React.useState('view');

  const loadGrants = React.useCallback(() => {
    return window.ZAMPP_API.fetch('/projects/' + project.id + '/access')
      .then(list => setGrants(list || []))
      .catch(e => setErr(e.message));
  }, [project.id]);

  React.useEffect(() => {
    setLoading(true);
    Promise.all([
      loadGrants(),
      window.ZAMPP_API.fetch('/users').then(setUsers).catch(() => setUsers([])),
      window.ZAMPP_API.fetch('/groups').then(setGroups).catch(() => setGroups([])),
    ]).finally(() => setLoading(false));
  }, [loadGrants]);

  const addGrant = () => {
    if (!subjId) return;
    setErr(null);
    window.ZAMPP_API.fetch('/projects/' + project.id + '/access', {
      method: 'POST',
      body: JSON.stringify({ subject_type: subjType, subject_id: subjId, level }),
    })
      .then(() => { setSubjId(''); return loadGrants(); })
      .catch(e => setErr(e.message || 'Failed to add grant'));
  };

  const revoke = (g) => {
    window.ZAMPP_API.fetch('/projects/' + project.id + '/access/' + g.subject_type + '/' + g.subject_id, { method: 'DELETE' })
      .then(loadGrants)
      .catch(e => setErr(e.message || 'Failed to revoke'));
  };

  // Candidates for the picker — exclude subjects that already have a grant.
  const grantedIds = new Set(grants.filter(g => g.subject_type === subjType).map(g => g.subject_id));
  const candidates = (subjType === 'user' ? users : groups).filter(c => !grantedIds.has(c.id));

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ width: 520 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ fontSize: 15, fontWeight: 600 }}>Manage access · {project.name}</div>
          <button className="icon-btn" aria-label="Close" onClick={onClose}><Icon name="x" /></button>
        </div>
        <div className="modal-body">
          <div style={{ fontSize: 12, color: 'var(--text-3)', marginBottom: 12 }}>
            Admins always have full access. Grant specific users or groups view (read-only) or
            edit (read-write) access to this project.
          </div>

          {/* Add-grant row */}
          <div style={{ display: 'grid', gridTemplateColumns: '90px 1fr 90px auto', gap: 8, alignItems: 'end', marginBottom: 14 }}>
            <div className="field" style={{ marginBottom: 0 }}>
              <label className="field-label">Type</label>
              <select className="field-input" value={subjType} style={{ appearance: 'auto' }}
                      onChange={e => { setSubjType(e.target.value); setSubjId(''); }}>
                <option value="user">User</option>
                <option value="group">Group</option>
              </select>
            </div>
            <div className="field" style={{ marginBottom: 0 }}>
              <label className="field-label">{subjType === 'user' ? 'User' : 'Group'}</label>
              <select className="field-input" value={subjId} style={{ appearance: 'auto' }}
                      onChange={e => setSubjId(e.target.value)}>
                <option value="">Pick a {subjType}…</option>
                {candidates.map(c => (
                  <option key={c.id} value={c.id}>
                    {subjType === 'user' ? ('@' + c.username + (c.display_name ? ' · ' + c.display_name : '')) : c.name}
                  </option>
                ))}
              </select>
            </div>
            <div className="field" style={{ marginBottom: 0 }}>
              <label className="field-label">Level</label>
              <select className="field-input" value={level} style={{ appearance: 'auto' }}
                      onChange={e => setLevel(e.target.value)}>
                <option value="view">View</option>
                <option value="edit">Edit</option>
              </select>
            </div>
            <button className="btn primary sm" onClick={addGrant} disabled={!subjId}>Add</button>
          </div>

          {err && <div style={{ fontSize: 12, color: 'var(--danger)', marginBottom: 8 }}>{err}</div>}

          {/* Existing grants */}
          <div className="panel">
            {loading && <div style={{ padding: 16, color: 'var(--text-3)', fontSize: 12.5 }}>Loading…</div>}
            {!loading && grants.length === 0 && (
              <div style={{ padding: '20px 0', textAlign: 'center', color: 'var(--text-3)', fontSize: 12.5 }}>
                No grants yet — only admins can see this project.
              </div>
            )}
            {!loading && grants.map(g => (
              <div key={g.subject_type + ':' + g.subject_id}
                   style={{ display: 'grid', gridTemplateColumns: '20px 1fr 70px 80px', gap: 10, alignItems: 'center', padding: '10px 14px', borderBottom: '1px solid var(--border)' }}>
                <Icon name={g.subject_type === 'group' ? 'users' : 'user'} size={13} />
                <div>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>{g.subject_name || '(deleted)'}</div>
                  {g.username && <div className="mono" style={{ fontSize: 11, color: 'var(--text-3)' }}>@{g.username}</div>}
                </div>
                <span className={`badge ${g.level === 'edit' ? 'accent' : 'neutral'}`}>{g.level}</span>
                <button className="btn ghost sm danger" onClick={() => revoke(g)}>Revoke</button>
              </div>
            ))}
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn primary sm" onClick={onClose}>Done</button>
        </div>
      </div>
    </div>
  );
}

function RenameProjectModal({ project, onClose, onSaved }) {
  const [name, setName] = React.useState(project.name || '');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const submit = () => {
    const trimmed = name.trim();
    if (!trimmed || trimmed === project.name) { onClose(); return; }
    setSaving(true); setErr(null);
    window.ZAMPP_API.fetch('/projects/' + project.id, { method: 'PATCH', body: JSON.stringify({ name: trimmed }) })
      .then(onSaved)
      .catch(e => { setSaving(false); setErr(e.message); });
  };
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ width: 420 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ fontSize: 15, fontWeight: 600 }}>Rename project</div>
          <button className="icon-btn" aria-label="Close" onClick={onClose}><Icon name="x" /></button>
        </div>
        <div className="modal-body">
          <div className="field">
            <label className="field-label">Project name</label>
            <input className="field-input" autoFocus value={name}
                   onChange={e => setName(e.target.value)}
                   onKeyDown={e => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') onClose(); }} />
          </div>
          {err && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 4 }}>{err}</div>}
        </div>
        <div className="modal-foot">
          <button className="btn ghost sm" onClick={onClose}>Cancel</button>
          <button className="btn primary sm" onClick={submit} disabled={saving || !name.trim()}>{saving ? 'Saving…' : 'Rename'}</button>
        </div>
      </div>
    </div>
  );
}

function ProjectCard({ project, assets, onOpen, onRename, onManageAccess, onDelete, canManageAccess }) {
  const ofProject = assets.filter(a => a.project_id === project.id);
  const thumbAssets = ofProject.slice(0, 4);

  // Real status distribution - ready vs processing/live vs error.
  const total = ofProject.length || 1;
  const ready      = ofProject.filter(a => a.status === 'ready').length;
  const inFlight   = ofProject.filter(a => a.status === 'processing' || a.status === 'live').length;
  const errored    = ofProject.filter(a => a.status === 'error').length;
  const readyPct    = (ready / total) * 100;
  const inFlightPct = (inFlight / total) * 100;
  const errPct      = (errored / total) * 100;

  // #50: context menu state for grid card
  const [ctx, setCtx] = React.useState(null);
  React.useEffect(() => {
    if (!ctx) return;
    const close = () => setCtx(null);
    window.addEventListener('click', close);
    window.addEventListener('contextmenu', close);
    window.addEventListener('scroll', close, true);
    return () => {
      window.removeEventListener('click', close);
      window.removeEventListener('contextmenu', close);
      window.removeEventListener('scroll', close, true);
    };
  }, [ctx]);

  const handleContextMenu = (e) => {
    e.preventDefault();
    e.stopPropagation();
    setCtx({ x: e.clientX, y: e.clientY });
  };

  return (
    <div className="project-card" onClick={onOpen} onContextMenu={handleContextMenu}>
      <div className="project-thumb-grid">
        {Array.from({ length: 4 }).map((_, i) => (
          <div key={i} className="project-thumb-cell">
            {thumbAssets[i]
              ? <AssetThumb asset={thumbAssets[i]} />
              : <FauxFrame />}
          </div>
        ))}
      </div>
      <div className="project-card-body">
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ width: 10, height: 10, borderRadius: 2, background: project.color || 'var(--accent)' }} />
          <span style={{ fontWeight: 600, fontSize: 14 }}>{project.name}</span>
        </div>
        <div className="project-meta">
          <span>{ofProject.length} asset{ofProject.length === 1 ? '' : 's'}</span>
          <span>·</span>
          <span>updated {project.updated || '·'}</span>
        </div>
        {ofProject.length > 0 ? (
          <div className="project-bar" title={`ready ${ready} · in-flight ${inFlight} · errored ${errored}`}>
            {ready    > 0 && <div className="project-segment" style={{ width: readyPct    + '%', background: 'var(--success)' }} />}
            {inFlight > 0 && <div className="project-segment" style={{ width: inFlightPct + '%', background: 'var(--accent)' }} />}
            {errored  > 0 && <div className="project-segment" style={{ width: errPct      + '%', background: 'var(--danger)' }} />}
          </div>
        ) : (
          <div className="project-bar"><div className="project-segment" style={{ width: '100%', background: 'var(--bg-3)' }} /></div>
        )}
      </div>
      {ctx && (
        <div className="row-menu" style={{ position: 'fixed', top: ctx.y, left: ctx.x, zIndex: 9999 }} onClick={e => e.stopPropagation()}>
          <button onClick={() => { setCtx(null); onOpen(); }}><Icon name="library" size={11} />Open</button>
          <button onClick={() => { setCtx(null); onRename && onRename(); }}><Icon name="edit" size={11} />Rename…</button>
          {canManageAccess && <button onClick={() => { setCtx(null); onManageAccess && onManageAccess(); }}><Icon name="users" size={11} />Manage access…</button>}
          <button className="danger" onClick={() => { setCtx(null); onDelete && onDelete(); }}><Icon name="trash" size={11} />Delete</button>
        </div>
      )}
    </div>
  );
}

window.Projects = Projects;
window.RenameProjectModal = RenameProjectModal;
window.ProjectAccessModal = ProjectAccessModal;
