// =============================================================
// Job Card
// =============================================================

function JobCard({ job, selected, bulkMode, bulkChecked, onSelect, onOpenDetail,
                   onIgnore, onUnignore, onMarkApplied, onCoverLetter,
                   onSubmitCoverLetter, onAcceptCoverLetter, onCancelCoverLetter,
                   onUpdateCoverLetter, onUpdateNotes, onToggleStar, scoreViz, density }) {
  const isCoverFlow = job._coverFlow; // 'form' | 'loading' | 'preview'

  // Local state for the "I'm being dragged" visual. We can't read it from
  // the DOM reliably across browsers, so we mirror it in React state.
  const [dragging, setDragging] = React.useState(false);

  // Drag is disabled when:
  //   - bulk mode is active (clicking is for selection, not dragging)
  //   - cover-letter flow is mid-form/loading/preview (would lose the inline UI)
  const dragDisabled = bulkMode || !!isCoverFlow;

  const handleCardClick = (e) => {
    if (e.target.closest('button') || e.target.closest('a') || e.target.closest('.bulk-check')
      || e.target.closest('.cl-inline')) return;
    if (bulkMode) { onSelect(); return; }
    onOpenDetail();
  };

  // Cancel the drag if it started from an interactive child (button, link, the
  // bulk checkbox, the inline cover-letter form). Without this, grabbing the
  // star icon would still initiate a drag of the whole card.
  const handleDragStart = (e) => {
    if (dragDisabled
        || e.target.closest('button')
        || e.target.closest('a')
        || e.target.closest('.bulk-check')
        || e.target.closest('.cl-inline')
        || e.target.closest('input, textarea, select')) {
      e.preventDefault();
      return;
    }
    // Stash the job id on the drag event so the receiving column knows what
    // was dropped. text/plain has the broadest cross-browser support.
    e.dataTransfer.setData('text/plain', job.id);
    e.dataTransfer.setData('application/x-jobmatcher-id', job.id);
    e.dataTransfer.effectAllowed = 'move';
    setDragging(true);
  };
  const handleDragEnd = () => setDragging(false);

  const isIgnoredStyle = job.status === 'ignored' || job.status === 'rejected';

  return (
    <div className={`job-card${selected ? ' selected' : ''}${isIgnoredStyle ? ' ignored-style' : ''}${job.starred ? ' starred' : ''}${bulkChecked ? ' bulk-checked' : ''}${dragging ? ' dragging' : ''}`}
         onClick={handleCardClick}
         draggable={!dragDisabled}
         onDragStart={handleDragStart}
         onDragEnd={handleDragEnd}>
      <div className={`bulk-check${bulkChecked ? ' checked' : ''}`}
           onClick={(e) => { e.stopPropagation(); onSelect(); }}>
        {bulkChecked && <Icon.check />}
      </div>

      <div className="card-top">
        <div className="company">{job.company || 'Unknown'}</div>
        <div className="card-top-right">
          <div className="posted">{job.posted}</div>
          <button className={`star-btn${job.starred ? ' on' : ''}`}
            onClick={(e) => { e.stopPropagation(); onToggleStar && onToggleStar(); }}
            title={job.starred ? 'Unstar' : 'Star'}>
            {job.starred ? <Icon.starFilled /> : <Icon.star />}
          </button>
        </div>
      </div>

      <h3 className="title">{job.title}</h3>

      <div className="card-scores">
        <ScoreViz cv={job.cvFitness} match={job.matchScore} variant={scoreViz} />
        <div className="card-scores-text">
          <div className="label">
            <span>CV fit</span>
            <div className="score-bar fitness"><div className="fill" style={{ width: `${job.cvFitness}%` }}></div></div>
            <span className="v">{Math.round(job.cvFitness)}</span>
          </div>
          <div className="label">
            <span>Match</span>
            <div className="score-bar match"><div className="fill" style={{ width: `${job.matchScore}%` }}></div></div>
            <span className="v">{Math.round(job.matchScore)}</span>
          </div>
        </div>
      </div>

      {job.salary && (
        <div className="salary">
          <span className="label">Salary</span>
          <span className="v">{job.salary}</span>
        </div>
      )}
      {!job.salary && density !== 'compact' && (
        <div className="salary">
          <span className="label">Salary</span>
          <span className="empty">not stated</span>
        </div>
      )}

      {job.oneLineReason && density !== 'compact' && (
        <div className="reason">{job.oneLineReason}</div>
      )}

      <div className="tag-row">
        {job.isRemote && <span className="tag remote">Remote</span>}
        {!job.isRemote && job.location && (
          <span className="tag"><Icon.location style={{ width: 10, height: 10 }} />{shortLoc(job.location)}</span>
        )}
        {job.seniority && job.seniority !== 'Not Applicable' && (
          <span className="tag seniority">{job.seniority}</span>
        )}
        {job.employment && job.employment !== 'Full-time' && (
          <span className="tag">{job.employment}</span>
        )}
      </div>

      <CardActions job={job} onIgnore={onIgnore} onUnignore={onUnignore}
        onMarkApplied={onMarkApplied} onCoverLetter={onCoverLetter}
        onOpenDetail={onOpenDetail} />

      {isCoverFlow && (
        <CoverLetterInline
          job={job}
          state={job._coverFlow}
          onSubmit={onSubmitCoverLetter}
          onAccept={onAcceptCoverLetter}
          onCancel={onCancelCoverLetter}
          onUpdateText={onUpdateCoverLetter}
          onUpdateNotes={onUpdateNotes}
        />
      )}
    </div>
  );
}

function shortLoc(loc) {
  if (!loc) return '';
  const parts = loc.split(',').map(s => s.trim());
  return parts[0];
}

// =============================================================
// Card actions row (varies by status)
// =============================================================
function CardActions({ job, onIgnore, onUnignore, onMarkApplied, onCoverLetter, onOpenDetail }) {
  const linkedinBtn = (
    <a className="action-btn" href={job.jobLink || '#'} target="_blank" rel="noopener noreferrer"
       onClick={(e) => e.stopPropagation()}>
      <span className="linkedin-icon">in</span>
      <span>LinkedIn</span>
    </a>
  );

  switch (job.status) {
    case 'ignored':
      return (
        <div className="card-actions">
          {linkedinBtn}
          <div className="spacer"></div>
          <button className="action-btn" onClick={onUnignore}><Icon.arrow style={{ transform: 'rotate(180deg)' }} /> Restore</button>
        </div>
      );
    case 'rejected':
      return (
        <div className="card-actions">
          {linkedinBtn}
          <div className="spacer"></div>
          <button className="action-btn" onClick={onIgnore}>Archive</button>
        </div>
      );
    case 'applied':
    case 'interviewing':
      return (
        <div className="card-actions">
          {linkedinBtn}
          <div className="spacer"></div>
          <button className="action-btn" onClick={onOpenDetail}>Details</button>
        </div>
      );
    case 'cover_letter':
      return (
        <div className="card-actions">
          {linkedinBtn}
          <div className="spacer"></div>
          <button className="action-btn primary" onClick={onMarkApplied}>
            <Icon.check /> Mark applied
          </button>
        </div>
      );
    case 'new':
    default:
      return (
        <div className="card-actions">
          {linkedinBtn}
          <div className="spacer"></div>
          <button className="action-btn danger" onClick={onIgnore} title="Ignore">
            <Icon.archive />
          </button>
          <button className="action-btn primary" onClick={onCoverLetter}>
            <Icon.letter /> Cover letter
          </button>
        </div>
      );
  }
}

// =============================================================
// Inline cover-letter form / loading / preview
// =============================================================
function CoverLetterInline({ job, state, onSubmit, onAccept, onCancel, onUpdateText, onUpdateNotes }) {
  const [loadingStep, setLoadingStep] = React.useState(0);
  const editorRef = React.useRef(null);

  React.useEffect(() => {
    if (state === 'loading') {
      setLoadingStep(0);
      const steps = [600, 700, 800, 800];
      let i = 0;
      const tick = () => {
        i++;
        setLoadingStep(i);
        if (i < steps.length) {
          setTimeout(tick, steps[i]);
        } else {
          setTimeout(() => onSubmit && onSubmit(), 350);
        }
      };
      setTimeout(tick, steps[0]);
    }
  }, [state]);

  if (state === 'form') {
    return (
      <div className="cl-inline">
        <div className="cl-title"><Icon.letter /> Draft cover letter</div>
        <textarea
          autoFocus
          placeholder="Optional: notes to include — angle, projects to highlight, tone, etc."
          value={job.coverLetterNotes || ''}
          onChange={(e) => onUpdateNotes && onUpdateNotes(e.target.value)}
        />
        <div className="cl-actions">
          <button className="btn ghost sm" onClick={onCancel}>Cancel</button>
          <button className="btn accent sm" onClick={onSubmit}>
            <Icon.letter /> Generate
          </button>
        </div>
      </div>
    );
  }

  if (state === 'loading') {
    const stepLabels = [
      'Fetching CV + preferences from Docs…',
      'Analysing job description…',
      'Drafting opening + body…',
      'Refining tone, polishing close…',
    ];
    return (
      <div className="cl-inline">
        <div className="cl-loading">
          <div className="spinner"></div>
          <div className="steps">
            {stepLabels.map((s, i) => (
              <div key={i} className={`step ${i < loadingStep ? 'done' : (i === loadingStep ? 'active' : '')}`}>
                {i < loadingStep ? '✓ ' : (i === loadingStep ? '→ ' : '  ')}{s}
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  if (state === 'preview') {
    return (
      <div className="cl-inline">
        <div className="cl-title">
          <Icon.letter /> Draft ready — review &amp; edit
          <span style={{ marginLeft: 'auto', color: 'var(--text-faint)', fontSize: 10 }}>
            click to edit
          </span>
        </div>
        <div
          ref={editorRef}
          className="cl-preview"
          contentEditable
          suppressContentEditableWarning
          onBlur={(e) => onUpdateText && onUpdateText(e.target.innerText)}
          dangerouslySetInnerHTML={{ __html: (job.coverLetter || '').replace(/\n/g, '<br/>') }}
        ></div>
        <div className="cl-actions">
          <button className="btn ghost sm" onClick={onCancel}>Discard</button>
          <button className="btn sm" onClick={() => {
            navigator.clipboard && navigator.clipboard.writeText(job.coverLetter || '');
          }}>Copy</button>
          <button className="btn accent sm" onClick={onAccept}>
            <Icon.check /> Save &amp; mark drafted
          </button>
        </div>
      </div>
    );
  }
  return null;
}

// =============================================================
// Column
// =============================================================
function KanbanColumn({ status, jobs, collapsed, onToggleCollapse, children, statusLabel, statusColor, onDropJob }) {
  // `dragDepth` is a small counter trick: dragenter/dragleave fire for every
  // child element you cross, so a naive boolean flickers as you move over
  // the cards inside the column. We increment on enter, decrement on leave,
  // and treat anything > 0 as "drag is hovering over me". This is the
  // standard workaround for the messy HTML5 DnD event model.
  const [dragDepth, setDragDepth] = React.useState(0);
  const isDragOver = dragDepth > 0;

  const handleDragOver = (e) => {
    // Must preventDefault on dragover for the drop event to fire at all.
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
  };
  const handleDragEnter = (e) => {
    e.preventDefault();
    setDragDepth((d) => d + 1);
  };
  const handleDragLeave = () => setDragDepth((d) => Math.max(0, d - 1));
  const handleDrop = (e) => {
    e.preventDefault();
    setDragDepth(0);
    const id = e.dataTransfer.getData('application/x-jobmatcher-id')
            || e.dataTransfer.getData('text/plain');
    if (!id || !onDropJob) return;
    onDropJob(id, status);
  };

  return (
    <div className={`column${collapsed ? ' collapsed' : ''}${isDragOver ? ' drag-over' : ''}`}
         onDragOver={handleDragOver}
         onDragEnter={handleDragEnter}
         onDragLeave={handleDragLeave}
         onDrop={handleDrop}>
      <div className="col-header" onClick={collapsed ? onToggleCollapse : undefined}>
        <div className="col-status-pip" style={{ background: statusColor }}></div>
        <div className="col-header-text">
          <div className="col-name">{statusLabel}</div>
          <div className="col-count mono">{jobs.length}</div>
        </div>
        <div className="col-vertical-label">{statusLabel}</div>
        <div className="col-vertical-count mono">{jobs.length}</div>
        <div className="col-header-actions">
          <button className="icon-btn" style={{ width: 24, height: 24 }} onClick={onToggleCollapse}
            title={collapsed ? 'Expand' : 'Collapse'}>
            {collapsed ? <Icon.chevRight /> : <Icon.chevLeft />}
          </button>
        </div>
      </div>
      <div className="col-body">
        {jobs.length === 0 ? (
          <div className="col-empty">
            <div>{isDragOver ? 'Drop to move here' : 'Nothing here'}</div>
            <div className="mono">— · —</div>
          </div>
        ) : children}
      </div>
    </div>
  );
}

Object.assign(window, { JobCard, KanbanColumn, CoverLetterInline, shortLoc });
