import { useState, useEffect, useRef } from 'react';
import { useParams, Link } from 'react-router-dom';
import Layout from '../components/Layout';
import PageLoader from '../components/PageLoader';
import ProfileAvatar from '../components/ProfileAvatar';
import StatusBadge from '../components/StatusBadge';
import { useAuth } from '../context/AuthContext';
import { supabase } from '../lib/supabase';
import { logActivity } from '../lib/activityLog';
import JSZip from 'jszip';
import { popupOverlayStyle, popupSurfaceStyle } from '../lib/popupStyles';
import { useLiveRefresh } from '../hooks/useLiveRefresh';
import { useActionLock } from '../hooks/useActionLock';
import FileAttachment from '../components/FileAttachment';
import { sendTaskStatusUpdate } from '../lib/taskNotifications';
import { encodeRejectedNote, parseRejectedNote, isReviewShadowSubmission, REVIEW_SHADOW_PREFIX, getVisibleTaskSubmissions, getTaskDerivedState } from '../lib/taskVersions';
import { getCurrentVersionForTask } from '../lib/taskDeadlines';
import { getSubmissionDisplayName, mergeSubmissionDisplayNames } from '../lib/submissionDisplay';

const ACTION_LABEL = {
  task_created: 'created this task', task_started: 'started this task', task_on_hold: 'placed task on hold',
  task_resumed: 'resumed this task', task_submitted: 'submitted this task', task_approved: 'approved this task',
  revision_requested: 'rejected this task', request_submitted: 'submitted this request',
  task_released: 'released this task',
};

const ACTION_ICON = {
  task_started:       { bg: 'color-mix(in srgb, var(--info) 15%, transparent)',  color: 'var(--info)', path: 'M6 4l14 8-14 8V4z' },
  task_resumed:       { bg: 'color-mix(in srgb, var(--info) 15%, transparent)',  color: 'var(--info)', path: 'M6 4l14 8-14 8V4z' },
  task_submitted:     { bg: 'color-mix(in srgb, var(--positive) 15%, transparent)',  color: 'var(--positive)', path: 'M12 19V5M5 12l7-7 7 7' },
  task_approved:      { bg: 'color-mix(in srgb, var(--positive) 15%, transparent)',  color: 'var(--positive)', path: 'M4 13l5 5L20 7' },
  task_on_hold:       { bg: 'color-mix(in srgb, var(--danger) 15%, transparent)',   color: 'var(--danger)', path: 'M6 4h4v16H6zM14 4h4v16h-4z' },
  task_released:      { bg: 'color-mix(in srgb, var(--danger) 15%, transparent)',   color: 'var(--danger)', path: 'M12 5v14M5 12h14' },
  task_created:       { bg: 'color-mix(in srgb, var(--violet) 15%, transparent)', color: 'var(--violet)', path: 'M12 5v14M5 12h14' },
  revision_requested: { bg: 'color-mix(in srgb, var(--warning) 15%, transparent)',  color: 'var(--warning)', path: 'M4 12a8 8 0 018-8v0a8 8 0 018 8' },
  request_submitted:  { bg: 'color-mix(in srgb, var(--violet) 15%, transparent)', color: 'var(--violet)', path: 'M9 12h6M9 8h6M5 3h14a2 2 0 012 2v14a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2z' },
};

function ActivityItem({ e }) {
  const icon = ACTION_ICON[e.action] || { bg: 'rgba(255,255,255,0.08)', color: 'rgba(255,255,255,0.4)', path: null };
  const label = ACTION_LABEL[e.action] || e.action;
  const actor = e.actor_name || 'Fourge';
  const d = new Date(e.created_at);
  const dateStr = d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
  const timeStr = d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
      <div style={{ width: 27, height: 27, borderRadius: '50%', background: icon.bg, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: 1 }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke={icon.color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          {icon.path && <path d={icon.path} />}
        </svg>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, lineHeight: 1.4 }}>
          <span style={{ color: 'var(--text-primary)', fontWeight: 500 }}>{actor}</span>
          <span style={{ color: 'var(--text-muted)' }}> {label}</span>
        </div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{dateStr} · {timeStr}</div>
      </div>
    </div>
  );
}

const CARD = { padding: '18px 21px', borderRadius: 8 };
const LABEL = { fontSize: 11, fontWeight: 500, color: 'var(--text-secondary)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 14 };
const META_LABEL = { fontSize: 11, fontWeight: 500, color: 'var(--text-secondary)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 4 };
const CARD_META_LABEL = { fontSize: 11, fontWeight: 500, color: 'var(--text-secondary)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 2 };
const MODAL_ACTION_ROW = { display: 'flex', gap: 8, justifyContent: 'flex-end', paddingTop: 4, flexWrap: 'nowrap' };
const MODAL_ACTION_BUTTON = { width: 132, justifyContent: 'center', flex: '0 0 132px' };

const TABS = ['Overview', 'Revisions', 'Submissions', 'Comments'];
function RejectedNoteBlock({ note }) {
  if (!note?.body) return null;
  const d = note.created_at ? new Date(note.created_at) : null;
  const dateStr = d ? d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : '—';
  return (
    <div style={{ padding: '12px 14px', borderRadius: 8, border: '1px solid color-mix(in srgb, var(--danger) 30%, var(--border))', background: 'color-mix(in srgb, var(--danger) 8%, var(--card-bg-2))' }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 6 }}>
        <div style={{ fontSize: 11, fontWeight: 500, color: 'var(--danger)', letterSpacing: 0.8, textTransform: 'uppercase' }}>Rejected Notes</div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', flexShrink: 0 }}>{dateStr}</div>
      </div>
      <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{note.body}</div>
    </div>
  );
}

function TimelineCard({ task, activityLog, currentSubmission }) {
  const status = task?.status;
  let currentStage;
  if (['client_approved', 'invoiced', 'paid'].includes(status)) currentStage = 4;
  else if (status === 'client_review') currentStage = 2;
  else if (status === 'in_progress' || status === 'on_hold') currentStage = 1;
  else currentStage = 0;

  const fmtDate = (d) => d ? new Date(d).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : null;

  // Only look at activity from the current revision cycle
  const lastRevision = activityLog.find(e => e.action === 'revision_requested');
  const cutoff = lastRevision ? new Date(lastRevision.created_at).getTime() : 0;
  const currentLog = activityLog.filter(e => new Date(e.created_at).getTime() > cutoff);

  const startedEntry = [...currentLog].reverse().find(e => e.action === 'task_started');
  const reviewEntry  = [...currentLog].reverse().find(e => e.action === 'task_submitted');

  const stages = [
    { label: 'Task Created',  date: fmtDate(currentSubmission?.submitted_at || task?.submitted_at) },
    { label: 'In Progress',   date: fmtDate(startedEntry?.created_at) },
    { label: 'In Review',     date: fmtDate(reviewEntry?.created_at) },
    { label: 'Approved',      date: fmtDate(task?.completed_at) },
  ];

  return (
    <div className="card" style={CARD}>
      <div style={LABEL}>Timeline</div>
      <div style={{ display: 'flex', flexDirection: 'column' }}>
        {stages.map((stage, i) => {
          const isDone = i < currentStage;
          const isCurrent = i === currentStage;
          let circle;
          if (isDone) {
            circle = (
              <div style={{ width: 22, height: 22, borderRadius: '50%', background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--text-on-accent)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="4,13 9,18 20,7"/></svg>
              </div>
            );
          } else if (isCurrent) {
            circle = (
              <div style={{ width: 22, height: 22, borderRadius: '50%', border: '2px solid var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <div style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--accent)' }} />
              </div>
            );
          } else {
            circle = <div style={{ width: 22, height: 22, borderRadius: '50%', border: '2px solid var(--border)', flexShrink: 0 }} />;
          }
          return (
            <div key={i} style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                {circle}
                {i < stages.length - 1 && (
                  <div style={{ width: 1, height: 26, background: isDone ? 'var(--accent)' : 'var(--border)', margin: '3px 0' }} />
                )}
              </div>
              <div style={{ paddingTop: 2, paddingBottom: i < stages.length - 1 ? 0 : 0 }}>
                <div style={{ fontSize: 12, fontWeight: 500, color: isDone || isCurrent ? 'var(--text-primary)' : 'var(--text-muted)' }}>{stage.label}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 1, marginBottom: 8 }}>{stage.date || '—'}</div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function AssigneePortrait({ name, avatarUrl }) {
  return <ProfileAvatar name={name} avatarUrl={avatarUrl} size={32} fontSize={12} />;
}

const fmtSize = (bytes) => {
  if (!bytes) return '';
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
};

const FILE_EXT_COLOR = { pdf: 'var(--danger)', jpg: 'var(--warning)', jpeg: 'var(--warning)', png: 'var(--data-blue)', gif: 'var(--data-purple)', svg: 'var(--data-emerald)', ai: 'var(--data-orange)', psd: 'var(--data-blue)', zip: 'var(--data-gray)', rar: 'var(--data-gray)', doc: 'var(--data-indigo)', docx: 'var(--data-indigo)', xls: 'var(--success-strong)', xlsx: 'var(--success-strong)', mp4: 'var(--data-pink)', mov: 'var(--data-pink)' };
const getExt = (name = '') => (name.split('.').pop() || '').toLowerCase();

function SubmissionFiles({ files, downloading, onDownloadAll }) {
  if (!files || files.length === 0) return null;
  return (
    <div style={{ marginTop: 14 }}>
      <div style={{ marginBottom: 8 }}>
        <div style={META_LABEL}>Attached Files ({files.length})</div>
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
        {files.map((file) => {
          const ext = getExt(file.name);
          const color = FILE_EXT_COLOR[ext] || 'var(--text-muted)';
          const label = ext ? ext.toUpperCase() : '—';
          return (
            <div key={file.id} title={`${file.name}${file.size ? ' · ' + fmtSize(file.size) : ''}`} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3, width: 40 }}>
              <div style={{ width: 32, height: 38, borderRadius: 5, background: 'var(--card-bg-2)', border: '1px solid var(--border)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 1 }}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
                <span style={{ fontSize: 6, fontWeight: 700, color, letterSpacing: 0.3 }}>{label}</span>
              </div>
              <div style={{ fontSize: 9, color: 'var(--text-muted)', width: '100%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', textAlign: 'center' }}>{file.name.replace(/\.[^.]+$/, '')}</div>
            </div>
          );
        })}
      </div>
      <button
        className="btn btn-outline"
        disabled={Boolean(downloading)}
        onClick={() => onDownloadAll(files)}
        style={{ marginTop: 10 }}
      >
        {downloading === 'all' ? 'Downloading…' : 'Download All'}
      </button>
    </div>
  );
}

function SubmissionSigns({ signs = [], signCount = null }) {
  const normalizedCount = Number(signCount || 0);
  if ((!signs || signs.length === 0) && normalizedCount <= 0) return null;
  return (
    <div>
      <div style={META_LABEL}>Signs</div>
      {signs && signs.length > 0 ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {signs
            .slice()
            .sort((a, b) => Number(a.sign_number || 0) - Number(b.sign_number || 0))
            .map((sign) => (
              <div key={sign.id || `${sign.sign_number}-${sign.sign_name}`} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.5 }}>
                  <span style={{ color: 'var(--text-secondary)', marginRight: 8 }}>Sign {sign.sign_number || '—'}</span>
                  <span>{sign.sign_name || 'Unnamed sign'}</span>
                </div>
                {sign.sign_family ? (
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.4 }}>
                    {sign.sign_family}
                  </div>
                ) : null}
              </div>
            ))}
        </div>
      ) : (
        <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.5 }}>
          N/A
        </div>
      )}
    </div>
  );
}

function normalizeSubmissionSigns(submission) {
  return (Array.isArray(submission?.signs) ? submission.signs : [])
    .map((sign, index) => ({
      ...sign,
      sign_number: Number(sign?.sign_number || index + 1),
      sign_name: String(sign?.sign_name || '').trim(),
      sign_family: String(sign?.sign_family || '').trim(),
    }))
    .filter(sign => sign.sign_name || sign.sign_family || Number.isFinite(sign.sign_number));
}

export default function TaskDetail() {
  const { id } = useParams();
  const { currentUser } = useAuth();
  const { refreshKey } = useLiveRefresh(['tasks', 'submissions', 'activity_log', 'task_comments']);
  const [task, setTask] = useState(null);
  const [submissions, setSubmissions] = useState([]);
  const [activityLog, setActivityLog] = useState([]);
  const [loading, setLoading] = useState(true);
  const [activeTab, setActiveTab] = useState('Overview');
  const [statusSaving, setStatusSaving] = useState(false);
  const guard = useActionLock();
  const [downloading, setDownloading] = useState('');
  const [revisionModal, setRevisionModal] = useState(false);
  const [revisionForm, setRevisionForm] = useState({ description: '', deadline: '' });
  const [revisionFiles, setRevisionFiles] = useState([]);
  const [revisionSaving, setRevisionSaving] = useState(false);
  const revisionFileRef = useRef(null);
  const [rejectModal, setRejectModal] = useState(false);
  const [rejectNote, setRejectNote] = useState('');
  const [rejectSaving, setRejectSaving] = useState(false);
  const [amendModal, setAmendModal] = useState(false);
  const [amendForm, setAmendForm] = useState({ description: '' });
  const [amendFiles, setAmendFiles] = useState([]);
  const [amendSaving, setAmendSaving] = useState(false);
  const [reviewModal, setReviewModal] = useState(false);
  const [reviewFiles, setReviewFiles] = useState([]);
  const [reviewNotes, setReviewNotes] = useState('');
  const [reviewSaving, setReviewSaving] = useState(false);
  const [comments, setComments] = useState([]);
  const [commentBody, setCommentBody] = useState('');
  const [commentSaving, setCommentSaving] = useState(false);
  const [deliveries, setDeliveries] = useState([]);
  const [dlProgress, setDlProgress] = useState({ active: false, label: '', percent: 0 });
  const canonicalTaskServiceType = getTaskDerivedState(task, submissions, deliveries).serviceType;

  const fetchTaskSubmissions = async (taskId) => {
    const { data: subRows } = await supabase
      .from('submissions')
      .select('id, type, version_number, request_key, submitted_by, submitted_by_name, submitted_at, service_type, deadline, description, is_hot, sign_family, sign_count, signs, files:submission_files(id, name, storage_path, size)')
      .eq('task_id', taskId)
      .order('submitted_at', { ascending: true });

    const submitterIds = [...new Set((subRows || []).map((submission) => submission.submitted_by).filter(Boolean))];
    if (submitterIds.length === 0) {
      return (subRows || []).map(submissionRow => ({ ...submissionRow, signs: normalizeSubmissionSigns(submissionRow) }));
    }

    const { data: submitterProfiles } = await supabase
      .from('profiles')
      .select('id, name')
      .in('id', submitterIds);

    return mergeSubmissionDisplayNames(
      (subRows || []).map(submissionRow => ({ ...submissionRow, signs: normalizeSubmissionSigns(submissionRow) })),
      submitterProfiles || []
    );
  };

  const reloadTaskRow = async () => {
    const { data } = await supabase
      .from('tasks')
      .select('*, project:projects(id, name, company:companies(id, name)), assignee:profiles!assigned_to(id, name, avatar_url)')
      .eq('id', id)
      .single();
    if (data) setTask(data);
  };

  useEffect(() => {
    Promise.all([
      supabase
        .from('tasks')
        .select('*, project:projects(id, name, company:companies(id, name)), assignee:profiles!assigned_to(id, name, avatar_url)')
        .eq('id', id)
        .single(),
      fetchTaskSubmissions(id),
      supabase
        .from('activity_log')
        .select('id, created_at, actor_id, actor_name, action, task_id, task_title')
        .eq('task_id', id)
        .order('created_at', { ascending: false })
        .limit(20),
      supabase
        .from('task_comments')
        .select('id, author_id, author_name, body, created_at')
        .eq('task_id', id)
        .order('created_at', { ascending: true }),
    ]).then(async ([{ data: taskData }, subRows, { data: actData }, { data: commentData }]) => {
      setTask(taskData);
      setSubmissions(subRows || []);
      setActivityLog(actData || []);
      setComments(commentData || []);
      const subIds = (subRows || []).map(s => s.id);
      if (subIds.length > 0) {
        const { data: delRows } = await supabase
          .from('deliveries')
          .select('*, files:delivery_files(id, name, storage_path, size)')
          .in('submission_id', subIds)
          .order('sent_at', { ascending: false });
        setDeliveries(delRows || []);
      }
      setLoading(false);
    });
  }, [id, refreshKey]);

  if (loading) return <Layout><PageLoader /></Layout>;
  if (!task) return <Layout><p style={{ padding: 24 }}>Task not found.</p></Layout>;

  const visibleSubmissions = getVisibleTaskSubmissions(submissions);
  const submission = visibleSubmissions.find(s => s.type === 'initial') || visibleSubmissions[0] || null;
  const rejectedNoteSubmissions = visibleSubmissions
    .filter(s => s.type === 'amendment' && parseRejectedNote(s.description))
    .map(s => ({ ...s, rejected: parseRejectedNote(s.description) }));
  const amendments = visibleSubmissions.filter(s => s.type === 'amendment' && !parseRejectedNote(s.description));
  const revisions = visibleSubmissions.filter(s => s.type === 'revision').sort((a, b) => a.version_number - b.version_number);
  const reviewSubmissions = deliveries;
  const commentRows = comments;
  const rejectedNoteByVersion = new Map(
    rejectedNoteSubmissions.map(note => [note.rejected.versionNumber, { ...note, body: note.rejected.body, created_at: note.submitted_at }])
  );
  const displayCurrentVersion = getCurrentVersionForTask(task, submissions);

  const assignee = task.assignee;
  const assigneeName = assignee?.name || task.assigned_name || null;
  const assigneeAvatar = assignee?.avatar_url || null;
  const project = task.project;
  const company = project?.company;
  const requester = getSubmissionDisplayName(submission) || null;
  const role = currentUser?.role;
  const isClient = role === 'client';
  const isTeamOrSub = role === 'team' || role === 'external';
  const status = task.status;
  const notificationBase = {
    taskId: id,
    taskTitle: task?.title || '',
    projectId: project?.id || '',
    projectName: project?.name || '',
    companyId: company?.id || '',
    companyName: company?.name || '',
    assignedProfileId: task?.assigned_to || currentUser?.id || '',
  };

  const actionBusy = statusSaving || reviewSaving || revisionSaving || rejectSaving || amendSaving;

  const log = (action) => logActivity({ actorId: currentUser.id, actorName: currentUser.name, action, taskId: id, taskTitle: task?.title, projectId: task?.project?.id, projectName: task?.project?.name });

  const updateStatus = guard('status', async (newStatus, extra = {}, action = null) => {
    setStatusSaving(true);
    const prevTask = task;
    setTask(t => ({ ...t, status: newStatus, ...extra }));
    try {
      const { error: taskUpdateError } = await supabase.from('tasks').update({ status: newStatus, ...extra }).eq('id', id);
      if (taskUpdateError) throw taskUpdateError;
      await reloadTaskRow();
      if (action) {
        await log(action);
        const { data } = await supabase.from('activity_log').select('id, created_at, actor_id, actor_name, action').eq('task_id', id).order('created_at', { ascending: false }).limit(20);
        setActivityLog(data || []);
      }
    } catch (err) {
      setTask(prevTask);
      console.error('Status update failed:', err);
      window.alert(err?.message || 'Failed to update status.');
      throw err;
    } finally {
      setStatusSaving(false);
    }
  });

  const handleStart = () => updateStatus('in_progress', { assigned_to: currentUser.id, assigned_name: currentUser.name }, 'task_started');
  const handleOnHold = async () => {
    await updateStatus('on_hold', {}, 'task_on_hold');
    sendTaskStatusUpdate({
      ...notificationBase,
      statusLabel: 'On Hold',
      headline: 'Task On Hold',
      subject: `Task On Hold: ${task?.title || 'Task'}`,
      message: `${currentUser.name} placed ${task?.title || 'this task'} on hold${project?.name ? ` for ${project.name}` : ''}.`,
      includeTeam: true,
      includeAssigned: true,
      includeClient: true,
    }).catch(() => {});
  };
  const handleResume = () => updateStatus('in_progress', {}, 'task_resumed');
  const handleSendToReview = () => { setReviewFiles([]); setReviewNotes(''); setReviewModal(true); };
  const handleRemoveFromReview = () => updateStatus('in_progress', {}, 'task_resumed');
  const handleConfirmReview = guard('review', async () => {
    setReviewSaving(true);
    try {
      const targetVersion = task.current_version || 0;
      const versionSubmissions = submissions.filter(s => (s.version_number || 0) === targetVersion && s.type !== 'amendment');
      const usedSubmissionIds = new Set(
        deliveries
          .filter(d => (d.version_number || 0) === targetVersion)
          .filter(d => versionSubmissions.some(s => s.id === d.submission_id))
          .map(d => d.submission_id)
      );
      let targetSubmission = versionSubmissions.find(s => !usedSubmissionIds.has(s.id)) || null;
      if (!targetSubmission) {
        const { data: createdSubmission, error: createdSubmissionError } = await supabase
          .from('submissions')
          .insert({
            task_id: id,
            version_number: targetVersion,
            type: targetVersion === 0 ? 'initial' : 'revision',
            revision_type: targetVersion > 0 ? 'client_revision' : null,
            service_type: canonicalTaskServiceType !== '—' ? canonicalTaskServiceType : null,
            description: `${REVIEW_SHADOW_PREFIX}${targetVersion}`,
            submitted_by: currentUser.id,
            submitted_by_name: currentUser.name,
          })
          .select('id, type, version_number, request_key, submitted_by, submitted_by_name, submitted_at, service_type, deadline, description, is_hot, sign_family, sign_count, signs')
          .single();
        if (createdSubmissionError) throw createdSubmissionError;
        targetSubmission = createdSubmission || null;
      }
      if (!targetSubmission?.id) throw new Error('No submission found for current version.');
      const { data: newDel, error: deliveryError } = await supabase
        .from('deliveries')
        .insert({ submission_id: targetSubmission.id, sent_by: currentUser.name, message: reviewNotes.trim() || '', version_number: targetVersion })
        .select()
        .single();
      if (deliveryError) throw deliveryError;
      if (!newDel?.id) throw new Error('Failed to create review submission.');
      if (newDel && reviewFiles.length > 0) {
        const uploaded = [];
        for (const file of reviewFiles) {
          const path = `${id}/${Date.now()}_${file.name}`;
          const { data: up, error: uploadError } = await supabase.storage.from('deliveries').upload(path, file);
          if (uploadError) throw uploadError;
          if (up) uploaded.push({ name: file.name, storage_path: path, size: file.size, delivery_id: newDel.id });
        }
        if (uploaded.length > 0) {
          const { error: deliveryFilesError } = await supabase.from('delivery_files').insert(uploaded);
          if (deliveryFilesError) throw deliveryFilesError;
        }
      }
      const refreshedSubRows = await fetchTaskSubmissions(id);
      const allSubRows = refreshedSubRows || [];
      setSubmissions(allSubRows);
      const subIds = allSubRows.map(s => s.id);
      const { data: delRows } = await supabase.from('deliveries').select('*, files:delivery_files(id, name, storage_path, size)').in('submission_id', subIds).order('sent_at', { ascending: false });
      setDeliveries(delRows || []);
      await updateStatus('client_review', {}, 'task_submitted');
      sendTaskStatusUpdate({
        ...notificationBase,
        statusLabel: 'In Review',
        headline: 'Task Ready For Review',
        subject: `In Review: ${task?.title || 'Task'}`,
        message: `${currentUser.name} placed ${task?.title || 'this task'} in review${project?.name ? ` for ${project.name}` : ''}.${reviewNotes.trim() ? ` Notes: ${reviewNotes.trim()}` : ''}`,
        includeTeam: true,
        includeAssigned: true,
        includeClient: true,
      }).catch(() => {});
      setReviewModal(false);
      setReviewFiles([]);
      setReviewNotes('');
    } catch (err) {
      console.error('Place in review failed:', err);
      window.alert(err?.message || 'Failed to place task in review.');
    } finally {
      setReviewSaving(false);
    }
  });
  const handleClientApprove = guard('approve', async () => {
    await updateStatus('client_approved', { completed_at: new Date().toISOString() }, 'task_approved');
    sendTaskStatusUpdate({
      ...notificationBase,
      statusLabel: 'Approved',
      headline: 'Task Approved',
      subject: `Approved: ${task?.title || 'Task'}`,
      message: `${currentUser.name} approved ${task?.title || 'this task'}${project?.name ? ` for ${project.name}` : ''}.`,
      includeTeam: true,
      includeAssigned: true,
      includeClient: true,
    }).catch(() => {});
  });
  const handleClientReject = () => { setRejectNote(''); setRejectModal(true); };
  const handleSubmitReject = guard('reject', async () => {
    if (!rejectNote.trim()) return;
    setRejectSaving(true);
    try {
      const rejectedVersion = task.current_version || 0;
      const { data: rejectedNoteSubmission, error: rejectNoteError } = await supabase
        .from('submissions')
        .insert({
          task_id: id,
          version_number: rejectedVersion,
          type: 'amendment',
          service_type: canonicalTaskServiceType !== '—' ? canonicalTaskServiceType : null,
          description: encodeRejectedNote(rejectedVersion, rejectNote.trim()),
          submitted_by: currentUser.id,
          submitted_by_name: currentUser.name,
        })
        .select()
        .single();
      // The rejection reason lives only in this submission row. If it didn't
      // save, do NOT flip status or log the rejection — otherwise the task
      // shows as "rejected" with no reason. Surface the error and bail.
      if (rejectNoteError || !rejectedNoteSubmission) {
        console.error('Reject note save failed:', rejectNoteError);
        window.alert(rejectNoteError?.message || 'Failed to save the rejection reason. The task was not rejected — please try again.');
        return;
      }
      setSubmissions(prev => [...prev, rejectedNoteSubmission]);
      await updateStatus('in_progress', {}, 'revision_requested');
      sendTaskStatusUpdate({
        ...notificationBase,
        statusLabel: 'Rejected',
        headline: 'Task Rejected',
        subject: `Rejected: ${task?.title || 'Task'}`,
        message: `${currentUser.name} rejected ${task?.title || 'this task'}${project?.name ? ` for ${project.name}` : ''}. Notes: ${rejectNote.trim()}`,
        includeTeam: true,
        includeAssigned: true,
        includeClient: true,
      }).catch(() => {});
      setRejectModal(false);
      setRejectNote('');
    } finally {
      setRejectSaving(false);
    }
  });
  const handleRelease = () => updateStatus('not_started', { assigned_to: null, assigned_name: null }, 'task_released');

  const handleSubmitRevision = guard('revision', async () => {
    setRevisionSaving(true);
    const baseline = Math.max(task.current_version || 0, ...submissions.map(s => s.version_number || 0));
    const newVersion = baseline + 1;
    await supabase.from('tasks').update({
      status: 'not_started',
      current_version: newVersion,
      assigned_to: task?.assigned_to || null,
      assigned_name: task?.assigned_name || task?.assignee?.name || null,
    }).eq('id', id);
    const { data: newSub } = await supabase.from('submissions').insert({ task_id: id, version_number: newVersion, type: 'revision', revision_type: 'client_revision', service_type: canonicalTaskServiceType !== '—' ? canonicalTaskServiceType : null, deadline: revisionForm.deadline || null, description: revisionForm.description, submitted_by: currentUser.id, submitted_by_name: currentUser.name }).select().single();
    if (newSub && revisionFiles.length > 0) {
      const uploadedFiles = [];
      for (const file of revisionFiles) {
        const path = `${id}/${newVersion}/${Date.now()}_${file.name}`;
        const { data: uploaded } = await supabase.storage.from('submissions').upload(path, file);
        if (uploaded) uploadedFiles.push({ name: file.name, storage_path: path, size: file.size });
      }
      if (uploadedFiles.length > 0) await supabase.from('submission_files').insert(uploadedFiles.map(f => ({ ...f, submission_id: newSub.id })));
    }
    await logActivity({ actorId: currentUser.id, actorName: currentUser.name, action: 'revision_requested', taskId: id, taskTitle: task?.title, projectId: project?.id, projectName: project?.name });
    const [{ data: taskData }, subRows, { data: actData }] = await Promise.all([
      supabase.from('tasks').select('*, project:projects(id, name, company:companies(id, name)), assignee:profiles!assigned_to(id, name, avatar_url)').eq('id', id).single(),
      fetchTaskSubmissions(id),
      supabase.from('activity_log').select('id, created_at, actor_id, actor_name, action, task_id, task_title').eq('task_id', id).order('created_at', { ascending: false }).limit(20),
    ]);
    setTask(taskData);
    setSubmissions(subRows || []);
    setActivityLog(actData || []);
    sendTaskStatusUpdate({
      ...notificationBase,
      assignedProfileId: task?.assigned_to || '',
      statusLabel: `Revision Request ${`R${String(newVersion).padStart(2, '0')}`}`,
      headline: 'Revision Requested',
      subject: `Revision Request: ${task?.title || 'Task'} ${`R${String(newVersion).padStart(2, '0')}`}`,
      message: `${currentUser.name} requested a revision for ${task?.title || 'this task'}${project?.name ? ` on ${project.name}` : ''}. ${revisionForm.description}`,
      includeTeam: true,
      includeAssigned: true,
      includeClient: true,
    }).catch(() => {});
    setRevisionModal(false);
    setRevisionForm({ description: '', deadline: '' });
    setRevisionFiles([]);
    setRevisionSaving(false);
  });

  const handleSubmitAmendment = guard('amend', async () => {
    if (!amendForm.description.trim()) return;
    setAmendSaving(true);
    setAmendModal(false);
    const baseline = Math.max(task.current_version || 0, ...submissions.map(s => s.version_number || 0));
    const { data: newSub } = await supabase.from('submissions').insert({ task_id: id, version_number: baseline, type: 'amendment', service_type: canonicalTaskServiceType !== '—' ? canonicalTaskServiceType : null, description: amendForm.description, submitted_by: currentUser.id, submitted_by_name: currentUser.name }).select().single();
    if (newSub && amendFiles.length > 0) {
      setDlProgress({ active: true, label: 'Uploading files…', percent: 0 });
      const uploaded = [];
      for (let i = 0; i < amendFiles.length; i++) {
        const file = amendFiles[i];
        setDlProgress({ active: true, label: file.name, percent: Math.round((i / amendFiles.length) * 100) });
        const path = `${id}/${Date.now()}_${file.name}`;
        const { data: up } = await supabase.storage.from('submissions').upload(path, file);
        if (up) uploaded.push({ name: file.name, storage_path: path, size: file.size });
      }
      if (uploaded.length > 0) await supabase.from('submission_files').insert(uploaded.map(f => ({ ...f, submission_id: newSub.id })));
      setDlProgress({ active: false, label: '', percent: 0 });
    }
    const subRows = await fetchTaskSubmissions(id);
    setSubmissions(subRows || []);
    sendTaskStatusUpdate({
      ...notificationBase,
      statusLabel: 'Request Amended',
      headline: 'Request Amended',
      subject: `Request Amended: ${task?.title || 'Task'}`,
      message: `${currentUser.name} amended ${task?.title || 'this task'}${project?.name ? ` for ${project.name}` : ''}. Notes: ${amendForm.description.trim()}`,
      includeTeam: true,
      includeAssigned: true,
      includeClient: true,
    }).catch(() => {});
    setAmendForm({ description: '' });
    setAmendFiles([]);
    setAmendSaving(false);
  });

  const handlePostComment = guard('comment', async () => {
    if (!commentBody.trim()) return;
    setCommentSaving(true);
    const { data } = await supabase.from('task_comments').insert({ task_id: id, author_id: currentUser.id, author_name: currentUser.name, body: commentBody.trim() }).select().single();
    if (data) setComments(prev => [...prev, data]);
    setCommentBody('');
    setCommentSaving(false);
  });

  const handleDeleteComment = async (commentId) => {
    await supabase.from('task_comments').delete().eq('id', commentId);
    setComments(prev => prev.filter(c => c.id !== commentId));
  };

  const downloadAllFiles = async (files, label = 'files', bucket = 'submissions') => {
    if (downloading) return;
    setDownloading('all');
    setDlProgress({ active: true, label: 'Preparing…', percent: 0 });
    try {
      const zip = new JSZip();
      for (let i = 0; i < files.length; i++) {
        const file = files[i];
        setDlProgress({ active: true, label: file.name, percent: Math.round((i / (files.length + 1)) * 100) });
        try {
          const { data } = await supabase.storage.from(bucket).createSignedUrl(file.storage_path, 3600, { download: file.name });
          if (data?.signedUrl) {
            const response = await fetch(data.signedUrl);
            if (response.ok) zip.file(file.name, await response.blob());
          }
        } catch { /* skip bad file */ }
      }
      setDlProgress({ active: true, label: 'Building zip…', percent: 95 });
      const content = await zip.generateAsync({ type: 'blob' });
      const zipName = `${task?.title || 'files'} ${label}.zip`.replace(/[^a-z0-9 ._-]/gi, '_');
      const a = document.createElement('a');
      a.href = URL.createObjectURL(content);
      a.download = zipName;
      a.click();
      URL.revokeObjectURL(a.href);
    } finally {
      setDlProgress({ active: false, label: '', percent: 0 });
      setDownloading('');
    }
  };

  return (
    <Layout>
      <div style={{ display: 'flex', gap: 24, alignItems: 'stretch', flex: 1, minHeight: 0, overflow: 'hidden' }}>
        <div style={{ flex: '0 0 70%', minWidth: 0, display: 'flex', flexDirection: 'column', gap: 24, minHeight: 0 }}>
          <div className="card" style={{ ...CARD, position: 'relative', ...(submission?.is_hot ? { background: 'radial-gradient(ellipse 90% 55% at 50% 120%, rgba(239,80,10,0.18) 0%, color-mix(in srgb, var(--accent) 9%, transparent) 45%, transparent 70%), var(--card-bg)' } : {}) }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 8 }}>
              <div style={{ fontSize: 28, fontWeight: 500, color: 'var(--text-primary)', lineHeight: 1.2 }}>{task.title}</div>
              <div style={{ display: 'flex', gap: 8, flexShrink: 0 }}>
                {isTeamOrSub && status === 'not_started' && (
                  <button className="btn btn-outline" disabled={actionBusy} onClick={handleStart}>Start Task</button>
                )}
                {isTeamOrSub && status === 'in_progress' && task.assigned_to === currentUser?.id && (
                  <>
                    <button className="btn btn-outline" disabled={actionBusy} onClick={handleRelease}>Release</button>
                    <button className="btn btn-outline" disabled={actionBusy} onClick={handleOnHold}>Place on Hold</button>
                    <button className="btn btn-primary" disabled={actionBusy} onClick={handleSendToReview}>Place in Review</button>
                  </>
                )}
                {isTeamOrSub && status === 'client_review' && task.assigned_to === currentUser?.id && (
                  <button className="btn btn-outline" disabled={actionBusy} onClick={handleRemoveFromReview}>Remove from Review</button>
                )}
                {isTeamOrSub && status === 'on_hold' && task.assigned_to === currentUser?.id && (
                  <>
                    <button className="btn btn-outline" disabled={actionBusy} onClick={handleRelease}>Release</button>
                    <button className="btn btn-outline" disabled={actionBusy} onClick={handleResume}>Resume</button>
                  </>
                )}
                {isClient && status === 'client_review' && (
                  <>
                    <button className="btn btn-primary" disabled={actionBusy} onClick={handleClientApprove}>Approve</button>
                    <button className="btn btn-danger" disabled={actionBusy} onClick={handleClientReject}>Reject</button>
                  </>
                )}
                {isClient && ['client_approved', 'invoiced', 'paid'].includes(status) && (
                  <button className="btn btn-outline" disabled={actionBusy} onClick={() => setRevisionModal(true)}>Request Revision</button>
                )}
              </div>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 20 }}>
              {canonicalTaskServiceType !== '—' && (
                <span className="badge badge-status badge-client">{canonicalTaskServiceType}</span>
              )}
              <StatusBadge status={task.status || 'not_started'} />
            </div>
            <div style={{ display: 'flex', gap: 30, flexWrap: 'wrap' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><line x1="4" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="20" y2="15"/><line x1="10" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="14" y2="21"/></svg>
                <div>
                  <div style={CARD_META_LABEL}>Task ID</div>
                  <div style={{ fontSize: 13, color: 'var(--text-primary)', fontVariantNumeric: 'tabular-nums' }}>{task.task_number || task.id.slice(0, 8).toUpperCase()}</div>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><polyline points="17,1 21,5 17,9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7,23 3,19 7,15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
                <div>
                  <div style={CARD_META_LABEL}>Revision</div>
                  <div style={{ fontSize: 13, color: 'var(--text-primary)', fontVariantNumeric: 'tabular-nums' }}>{displayCurrentVersion === 0 ? 'New' : String(displayCurrentVersion).padStart(2, '0')}</div>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
                <div>
                  <div style={CARD_META_LABEL}>Project</div>
                  {project
                    ? <Link to={`/projects/${project.id}`} className="table-link" style={{ fontSize: 13 }}>{project.name}</Link>
                    : <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>—</div>}
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
                <div>
                  <div style={CARD_META_LABEL}>Requested</div>
                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>
                    {submission?.submitted_at || task.submitted_at
                      ? new Date(submission?.submitted_at || task.submitted_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
                      : '—'}
                  </div>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><circle cx="12" cy="12" r="10"/><polyline points="12,6 12,12 16,14"/></svg>
                <div>
                  <div style={CARD_META_LABEL}>Due Date</div>
                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>
                    {submission?.deadline
                      ? new Date(submission.deadline).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
                      : '—'}
                  </div>
                </div>
              </div>
            </div>
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginBottom: 10 }}>
              {TABS.map(tab => {
                const count = tab === 'Revisions' ? revisions.length : tab === 'Submissions' ? reviewSubmissions.length : tab === 'Comments' ? commentRows.length : 0;
                return (
                  <button key={tab} onClick={() => setActiveTab(tab)} className={`section-tab-btn${activeTab === tab ? ' is-active' : ''}`}>
                    {tab}{count > 0 && <span style={{ marginLeft: 5, fontSize: 12, fontWeight: 600, color: activeTab === tab ? 'var(--accent)' : 'var(--text-muted)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 10, padding: '3px 8px' }}>{count}</span>}
                  </button>
                );
              })}
            </div>
            <div className="card" style={{ ...CARD, flex: 1, minHeight: 0, overflowY: 'auto' }}>
              <div style={{ fontSize: 13 }}>
                {activeTab === 'Overview' && (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
                    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 32 }}>
                      <div>
                        <div style={META_LABEL}>Requested By</div>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{requester || '—'}</div>
                      </div>
                      <div>
                        <div style={META_LABEL}>Requested</div>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>
                          {submission?.submitted_at ? new Date(submission.submitted_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : '—'}
                        </div>
                      </div>
                      <div>
                        <div style={META_LABEL}>Sign Count</div>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{submission?.sign_count > 0 ? submission.sign_count : 'N/A'}</div>
                      </div>
                      {isClient && ['not_started', 'in_progress'].includes(status) && (
                        <div style={{ marginLeft: 'auto' }}>
                          <button className="btn btn-outline" onClick={() => setAmendModal(true)}>Amend Request</button>
                        </div>
                      )}
                      {rejectedNoteByVersion.get(0) && (
                        <div style={{ marginLeft: 'auto', flex: '0 0 min(320px, 36%)' }}>
                          <RejectedNoteBlock note={rejectedNoteByVersion.get(0)} />
                        </div>
                      )}
                    </div>
                    {submission?.description && (
                      <div>
                        <div style={META_LABEL}>Notes</div>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{submission.description}</div>
                      </div>
                    )}
                    {submission?.sign_family && (
                      <div>
                        <div style={META_LABEL}>Sign Family</div>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{submission.sign_family}</div>
                      </div>
                    )}
                    <SubmissionSigns signs={submission?.signs} signCount={submission?.sign_count} />
                    <SubmissionFiles files={submission?.files} downloading={downloading} onDownloadAll={downloadAllFiles} />
                    {amendments.length > 0 && (
                      <div style={{ borderTop: '1px solid var(--border)', paddingTop: 20, display: 'flex', flexDirection: 'column', gap: 20 }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                          <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: 0.8, color: 'var(--text-secondary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 4, padding: '2px 8px', textTransform: 'uppercase' }}>Amendment</span>
                        </div>
                        {amendments.map((am) => (
                          <div key={am.id} style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
                            {am.description && (
                              <div>
                                <div style={META_LABEL}>Notes</div>
                                <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{am.description}</div>
                              </div>
                            )}
                            <SubmissionFiles files={am.files} downloading={downloading} onDownloadAll={downloadAllFiles} />
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                )}
                {activeTab === 'Revisions' && (
                  revisions.length === 0
                    ? <div className="card-empty-center">No revisions</div>
                    : <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
                        {[...revisions].reverse().map((rev, i, arr) => {
                          const rNum = `R${String(rev.version_number).padStart(2, '0')}`;
                          const fmtDate = rev.submitted_at
                            ? new Date(rev.submitted_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
                            : '—';
                          return (
                            <div key={rev.id} style={{ display: 'flex', flexDirection: 'column', gap: 20, borderBottom: i < arr.length - 1 ? '1px solid var(--border)' : 'none', paddingBottom: i < arr.length - 1 ? 20 : 0 }}>
                              <div style={{ display: 'flex', alignItems: 'flex-start', gap: 32 }}>
                                <div>
                                  <div style={META_LABEL}>Requested By</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{getSubmissionDisplayName(rev) || '—'}</div>
                                </div>
                                <div>
                                  <div style={META_LABEL}>Requested</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{fmtDate}</div>
                                </div>
                                <div>
                                  <div style={META_LABEL}>Sign Count</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{rev.sign_count > 0 ? rev.sign_count : 'N/A'}</div>
                                </div>
                                <div>
                                  <div style={META_LABEL}>Revision</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{rNum}</div>
                                </div>
                                {isClient && i === 0 && ['not_started', 'in_progress'].includes(status) && (
                                  <div style={{ marginLeft: 'auto' }}>
                                    <button className="btn btn-outline" onClick={() => setAmendModal(true)}>Amend</button>
                                  </div>
                                )}
                                {rejectedNoteByVersion.get(rev.version_number) && (
                                  <div style={{ marginLeft: 'auto', flex: '0 0 min(320px, 36%)' }}>
                                    <RejectedNoteBlock note={rejectedNoteByVersion.get(rev.version_number)} />
                                  </div>
                                )}
                              </div>
                              {rev.description && (
                                <div>
                                  <div style={META_LABEL}>Description</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{rev.description}</div>
                                </div>
                              )}
                              {rev.sign_family && (
                                <div>
                                  <div style={META_LABEL}>Sign Family</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{rev.sign_family}</div>
                                </div>
                              )}
                              <SubmissionSigns signs={rev.signs} signCount={rev.sign_count} />
                              {!rev.description && !rev.sign_family && !(rev.signs?.length > 0) && !(Number(rev.sign_count || 0) > 0) && (
                                <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>No notes provided.</div>
                              )}
                              <SubmissionFiles files={rev.files} downloading={downloading} onDownloadAll={(f) => downloadAllFiles(f, rNum)} />
                            </div>
                          );
                        })}
                      </div>
                )}
                {activeTab === 'Submissions' && (
                  reviewSubmissions.length === 0
                    ? <div className="card-empty-center">No submissions</div>
                    : <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
                        {reviewSubmissions.map((sub, i, arr) => {
                          const fmtDate = sub.sent_at
                            ? new Date(sub.sent_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
                            : '—';
                          return (
                            <div key={sub.id} style={{ display: 'flex', flexDirection: 'column', gap: 20, borderBottom: i < arr.length - 1 ? '1px solid var(--border)' : 'none', paddingBottom: i < arr.length - 1 ? 20 : 0 }}>
                              <div style={{ display: 'flex', alignItems: 'flex-start', gap: 32 }}>
                                <div>
                                  <div style={META_LABEL}>Submitted By</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{sub.sent_by || '—'}</div>
                                </div>
                                <div>
                                  <div style={META_LABEL}>Date</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)' }}>{fmtDate}</div>
                                </div>
                                <div>
                                  <div style={META_LABEL}>Version</div>
                                  <div style={{ fontSize: 13, color: 'var(--text-primary)', fontWeight: 500 }}>{`R${String(sub.version_number ?? 0).padStart(2, '0')}`}</div>
                                </div>
                              </div>
                              {sub.message
                                ? <div>
                                    <div style={META_LABEL}>Notes</div>
                                    <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{sub.message}</div>
                                  </div>
                                : <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>No notes provided.</div>
                              }
                              <SubmissionFiles files={sub.files} downloading={downloading} onDownloadAll={(f) => downloadAllFiles(f, `Submission ${i + 1}`, 'deliveries')} />
                            </div>
                          );
                        })}
                      </div>
                )}
                {activeTab === 'Comments' && (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
                    <div style={{ display: 'flex', gap: 8, marginBottom: 20 }}>
                      <input
                        type="text"
                        placeholder="Write a comment…"
                        value={commentBody}
                        onChange={e => setCommentBody(e.target.value)}
                        onKeyDown={e => { if (e.key === 'Enter') handlePostComment(); }}
                        style={{ flex: 1, fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', fontFamily: 'inherit', height: 30 }}
                      />
                      <button className="btn btn-outline" disabled={commentSaving || !commentBody.trim()} onClick={handlePostComment}>Post</button>
                    </div>
                    {comments.length === 0
                      ? <div className="card-empty-center">No comments</div>
                      : commentRows.map((c, i) => {
                          const d = new Date(c.created_at);
                          const dateStr = d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
                          const timeStr = d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
                          const isOwn = c.author_id === currentUser?.id;
                          return (
                            <div key={c.id} style={{ borderTop: '1px solid var(--border)', paddingTop: 20, paddingBottom: 20 }}>
                              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
                                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                                  <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--text-primary)' }}>{c.author_name}</span>
                                  <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{dateStr} · {timeStr}</span>
                                </div>
                                {isOwn && (
                                  <button className="btn btn-danger" onClick={() => handleDeleteComment(c.id)}>Delete</button>
                                )}
                              </div>
                              <div style={{ fontSize: 13, color: 'var(--text-primary)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{c.body}</div>
                            </div>
                          );
                        })
                    }
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>

        <div style={{ flex: '0 0 calc(30% - 24px)', minWidth: 0, display: 'flex', flexDirection: 'column', gap: 24, minHeight: 0 }}>
          <div className="card" style={CARD}>
            <div style={LABEL}>Assigned To</div>
            {assigneeName ? (
              <Link to={`/profile/${assignee?.id}`} className="dashboard-inline-link" style={{ display: 'flex', alignItems: 'center', gap: 10, textDecoration: 'none' }}>
                <AssigneePortrait name={assigneeName} avatarUrl={assigneeAvatar} />
                <span style={{ fontSize: 13, fontWeight: 500 }}>{assigneeName}</span>
              </Link>
            ) : (
              <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>Unassigned</div>
            )}
          </div>

          <TimelineCard task={task} activityLog={activityLog} currentSubmission={submission} />

          <div className="card" style={{ ...CARD, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
            <div style={LABEL}>Activity</div>
            {activityLog.length === 0 ? (
              <div className="card-empty-center">No activity</div>
            ) : (
              <div className="scrollbar-thin-theme" style={{ flex: 1, minHeight: 0, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 10 }}>
                {activityLog.map(e => (
                  <ActivityItem key={e.id} e={e} />
                ))}
              </div>
            )}
          </div>
        </div>
      </div>

      {reviewModal && (
        <div style={popupOverlayStyle} onClick={() => { if (!reviewSaving) { setReviewModal(false); setReviewFiles([]); setReviewNotes(''); } }}>
          <div style={{ ...popupSurfaceStyle, width: 'min(480px, 96vw)', maxHeight: 'calc(100vh - 48px)', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 14 }} onClick={e => e.stopPropagation()}>
            <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)' }}>Place in Review</div>
            <div>
              <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Notes <span style={{ color: 'var(--text-muted)', fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>(optional)</span></div>
              <textarea rows={4} placeholder="Add notes for this submission…" value={reviewNotes} onChange={e => setReviewNotes(e.target.value)} style={{ fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', width: '100%', fontFamily: 'inherit', boxSizing: 'border-box', resize: 'vertical' }} />
            </div>
            <div>
              <FileAttachment files={reviewFiles} onChange={setReviewFiles} />
            </div>
            <div className="modal-action-row" style={MODAL_ACTION_ROW}>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={reviewSaving} onClick={handleConfirmReview}>{reviewSaving ? 'Submitting…' : 'Place in Review'}</button>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={reviewSaving} onClick={() => { setReviewModal(false); setReviewFiles([]); setReviewNotes(''); }}>Cancel</button>
            </div>
          </div>
        </div>
      )}

      {revisionModal && (
        <div style={{ position: 'fixed', inset: 0, background: 'var(--overlay-scrim, rgba(0,0,0,0.58))', zIndex: 1200, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }} onClick={() => { if (!revisionSaving) { setRevisionModal(false); setRevisionForm({ description: '', deadline: '' }); setRevisionFiles([]); } }}>
          <div className="card" style={{ ...CARD, width: '100%', maxWidth: 480, display: 'flex', flexDirection: 'column', gap: 18 }} onClick={e => e.stopPropagation()}>
            <div style={{ fontSize: 18, fontWeight: 500, color: 'var(--text-primary)', letterSpacing: 0.2, lineHeight: 1.1 }}>Request Revision</div>
            <div className="form-group">
              <label style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)' }}>Revision Notes</label>
              <textarea
                rows={5}
                placeholder="Describe what needs to be changed…"
                value={revisionForm.description}
                onChange={e => setRevisionForm(f => ({ ...f, description: e.target.value }))}
                style={{ width: '100%', fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '8px 10px', resize: 'vertical', fontFamily: 'inherit' }}
              />
            </div>
            <div className="form-group">
              <label style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)' }}>Deadline</label>
              <input
                type="date"
                value={revisionForm.deadline}
                onChange={e => setRevisionForm(f => ({ ...f, deadline: e.target.value }))}
                style={{ fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', width: '100%' }}
              />
            </div>
            <div className="form-group">
              <FileAttachment files={revisionFiles} onChange={setRevisionFiles} />
            </div>
            <div className="modal-action-row" style={MODAL_ACTION_ROW}>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={revisionSaving} onClick={() => { setRevisionModal(false); setRevisionForm({ description: '', deadline: '' }); setRevisionFiles([]); }}>Cancel</button>
              <button className="btn btn-outline" style={{ ...MODAL_ACTION_BUTTON, color: 'var(--accent)', borderColor: 'var(--accent)' }} disabled={revisionSaving || !revisionForm.description.trim()} onClick={handleSubmitRevision}>
                {revisionSaving ? 'Submitting…' : 'Submit Revision'}
              </button>
            </div>
          </div>
        </div>
      )}

      {rejectModal && (
        <div style={popupOverlayStyle} onClick={() => { if (!rejectSaving) { setRejectModal(false); setRejectNote(''); } }}>
          <div style={{ ...popupSurfaceStyle, width: 'min(480px, 96vw)', maxHeight: 'calc(100vh - 48px)', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 16 }} onClick={e => e.stopPropagation()}>
            <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', lineHeight: 1.1 }}>Reject Task</div>
            <div>
              <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Rejected Notes</div>
              <textarea
                rows={5}
                placeholder="Tell the team what needs to change before approval…"
                value={rejectNote}
                onChange={e => setRejectNote(e.target.value)}
                style={{ width: '100%', fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '8px 10px', resize: 'vertical', fontFamily: 'inherit', boxSizing: 'border-box' }}
              />
            </div>
            <div className="modal-action-row" style={MODAL_ACTION_ROW}>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={rejectSaving} onClick={() => { setRejectModal(false); setRejectNote(''); }}>Cancel</button>
              <button className="btn btn-danger" style={MODAL_ACTION_BUTTON} disabled={rejectSaving || !rejectNote.trim()} onClick={handleSubmitReject}>
                {rejectSaving ? 'Saving…' : 'Reject'}
              </button>
            </div>
          </div>
        </div>
      )}

      {amendModal && (
        <div style={popupOverlayStyle} onClick={() => { setAmendModal(false); setAmendForm({ description: '' }); setAmendFiles([]); }}>
          <div style={{ ...popupSurfaceStyle, width: 'min(480px, 96vw)', maxHeight: 'calc(100vh - 48px)', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 16 }} onClick={e => e.stopPropagation()}>
            <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', lineHeight: 1.1 }}>Amend Request</div>
            <div>
              <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Notes</div>
              <textarea rows={4} placeholder="Describe what you'd like to add or change…" value={amendForm.description} onChange={e => setAmendForm(f => ({ ...f, description: e.target.value }))} style={{ width: '100%', fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '8px 10px', resize: 'vertical', fontFamily: 'inherit', boxSizing: 'border-box' }} />
            </div>
            <div>
              <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Attach Files</div>
              <FileAttachment files={amendFiles} onChange={setAmendFiles} />
            </div>
            <div className="modal-action-row" style={MODAL_ACTION_ROW}>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={amendSaving} onClick={handleSubmitAmendment}>{amendSaving ? 'Saving…' : 'Save'}</button>
              <button className="btn btn-outline" style={MODAL_ACTION_BUTTON} disabled={amendSaving} onClick={() => { setAmendModal(false); setAmendForm({ description: '' }); setAmendFiles([]); }}>Cancel</button>
            </div>
          </div>
        </div>
      )}

      {dlProgress.active && (
        <div style={{ position: 'fixed', inset: 0, background: 'var(--overlay-scrim, rgba(0,0,0,0.58))', zIndex: 1200, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
          <div className="card" style={{ ...CARD, width: '100%', maxWidth: 340, display: 'flex', flexDirection: 'column', gap: 12 }}>
            <div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)' }}>Downloading</div>
            <div style={{ fontSize: 12, color: 'var(--text-secondary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{dlProgress.label}</div>
            <div style={{ height: 4, borderRadius: 2, background: 'var(--card-bg-2)', overflow: 'hidden' }}>
              <div style={{ height: '100%', borderRadius: 2, background: 'var(--accent)', width: `${dlProgress.percent}%`, transition: 'width 200ms ease' }} />
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', textAlign: 'right' }}>{dlProgress.percent}%</div>
          </div>
        </div>
      )}
    </Layout>
  );
}
