import { ELECTIVE_SETS } from '../data/electiveSets';
import { SPECIALIZATIONS } from '../data/specializations';
import { coursesBySet } from '../data/lookups';
import type { Term } from '../data/types';
import type { SetAnalysis } from '../solver/decisionTree';

// Reverse map: courseId → specialization names that require it
const requiredForSpec: Record<string, string[]> = {};
for (const spec of SPECIALIZATIONS) {
  if (spec.requiredCourseId) {
    (requiredForSpec[spec.requiredCourseId] ??= []).push(spec.name);
  }
}

interface CourseSelectionProps {
  pinnedCourses: Record<string, string | null>;
  treeResults: SetAnalysis[];
  treeLoading: boolean;
  disabledCourseIds: Set<string>;
  onPin: (setId: string, courseId: string) => void;
  onUnpin: (setId: string) => void;
  onClearAll: () => void;
}

function ElectiveSet({
  setId,
  setName,
  pinnedCourseId,
  analysis,
  loading,
  disabledCourseIds,
  onPin,
  onUnpin,
}: {
  setId: string;
  setName: string;
  pinnedCourseId: string | null | undefined;
  analysis?: SetAnalysis;
  loading: boolean;
  disabledCourseIds: Set<string>;
  onPin: (courseId: string) => void;
  onUnpin: () => void;
}) {
  const courses = coursesBySet[setId];
  const isPinned = pinnedCourseId != null;
  const pinnedCourse = isPinned ? courses.find((c) => c.id === pinnedCourseId) : null;

  // Build a map from courseId to ceiling choice data
  const ceilingMap = new Map(
    (analysis?.choices ?? []).map((ch) => [ch.courseId, ch]),
  );
  const hasHighImpact = analysis && analysis.impact > 0;

  return (
    <div
      style={{
        border: isPinned ? '1px solid #3b82f6' : '1px solid #ccc',
        borderStyle: isPinned ? 'solid' : 'dashed',
        borderRadius: '8px',
        padding: '12px',
        marginBottom: '8px',
        background: isPinned ? '#eff6ff' : '#fafafa',
        transition: 'border-color 200ms, background-color 200ms',
      }}
    >
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
        <h4 style={{ fontSize: '13px', margin: 0, color: '#444' }}>
          {setName}
          {!isPinned && hasHighImpact && (
            <span style={{ fontSize: '11px', color: '#d97706', marginLeft: '8px', fontWeight: 400 }}>high impact</span>
          )}
        </h4>
        {isPinned && (
          <button
            onClick={onUnpin}
            style={{
              fontSize: '11px', border: '1px solid #bfdbfe', background: '#eff6ff',
              color: '#2563eb', cursor: 'pointer', padding: '3px 10px',
              borderRadius: '4px', fontWeight: 500,
            }}
          >
            Clear
          </button>
        )}
      </div>
      {/* Pinned view */}
      <div style={{
        maxHeight: isPinned ? '40px' : '0',
        opacity: isPinned ? 1 : 0,
        overflow: 'hidden',
        transition: 'max-height 250ms ease-out, opacity 200ms',
      }}>
        <div style={{ fontSize: '14px', fontWeight: 600, color: '#1e40af' }}>
          {pinnedCourse?.name}
        </div>
      </div>
      {/* Course list view */}
      <div style={{
        maxHeight: isPinned ? '0' : '500px',
        opacity: isPinned ? 0 : 1,
        overflow: 'hidden',
        pointerEvents: isPinned ? 'none' : 'auto',
        transition: 'max-height 250ms ease-out, opacity 200ms',
      }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
          {courses.map((course) => {
            const isCancelled = !!course.cancelled;
            const isDisabled = disabledCourseIds.has(course.id);
            const isUnavailable = isCancelled || isDisabled;
            const ceiling = ceilingMap.get(course.id);
            const reqFor = requiredForSpec[course.id];
            const showSkeleton = loading && !analysis;
            return (
              <button
                key={course.id}
                onClick={isUnavailable ? undefined : () => onPin(course.id)}
                disabled={isUnavailable}
                style={{
                  display: 'flex', flexDirection: 'column', alignItems: 'stretch',
                  textAlign: 'left', padding: '6px 10px',
                  border: '1px solid #e5e7eb', borderRadius: '4px',
                  background: isUnavailable ? '#f5f5f5' : '#fff',
                  cursor: isUnavailable ? 'default' : 'pointer',
                  fontSize: '13px',
                  color: isUnavailable ? '#bbb' : '#333',
                  pointerEvents: isUnavailable ? 'none' : 'auto',
                }}
              >
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '8px' }}>
                  <span style={{
                    flex: 1,
                    textDecoration: isCancelled ? 'line-through' : 'none',
                    fontStyle: isCancelled ? 'italic' : 'normal',
                  }}>
                    {course.name}
                    {isCancelled && (
                      <span style={{ fontSize: '11px', color: '#999', marginLeft: '6px', fontStyle: 'normal', textDecoration: 'none' }}>
                        (Cancelled)
                      </span>
                    )}
                    {!isCancelled && isDisabled && (
                      <span style={{ fontSize: '11px', color: '#999', marginLeft: '6px' }}>
                        (Already selected)
                      </span>
                    )}
                  </span>
                  {!isUnavailable && showSkeleton ? (
                    <span
                      style={{
                        display: 'inline-block',
                        width: '60px',
                        height: '14px',
                        borderRadius: '3px',
                        background: 'linear-gradient(90deg, #e5e7eb 25%, #f0f0f0 50%, #e5e7eb 75%)',
                        backgroundSize: '200% 100%',
                        animation: 'skeleton-pulse 1.5s ease-in-out infinite',
                      }}
                    />
                  ) : !isUnavailable && ceiling ? (
                    <span style={{
                      fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 600,
                      color: ceiling.ceilingCount >= 3 ? '#16a34a' : ceiling.ceilingCount >= 2 ? '#2563eb' : '#666',
                    }}>
                      {ceiling.ceilingCount} spec{ceiling.ceilingCount !== 1 ? 's' : ''}
                      {ceiling.ceilingSpecs.length > 0 && (
                        <span style={{ fontWeight: 400, color: '#888', marginLeft: '3px' }}>
                          ({ceiling.ceilingSpecs.join(', ')})
                        </span>
                      )}
                    </span>
                  ) : null}
                </div>
                {reqFor && !isUnavailable && (
                  <span style={{ fontSize: '11px', color: '#92400e', marginTop: '2px' }}>
                    Required for {reqFor.join(', ')}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

const skeletonStyle = `@keyframes skeleton-pulse { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }`;

export function CourseSelection({ pinnedCourses, treeResults, treeLoading, disabledCourseIds, onPin, onUnpin, onClearAll }: CourseSelectionProps) {
  const terms: Term[] = ['Spring', 'Summer', 'Fall'];
  const hasPinned = Object.keys(pinnedCourses).length > 0;

  // Index tree results by setId for O(1) lookup
  const treeBySet = new Map(treeResults.map((a) => [a.setId, a]));

  return (
    <div>
      <style>{skeletonStyle}</style>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
        <div>
          <h2 style={{ fontSize: '16px', margin: 0 }}>Course Selection</h2>
          <p style={{ fontSize: '12px', color: '#888', margin: '2px 0 0' }}>Select one course per elective slot. Analysis shows how each choice affects your specializations.</p>
        </div>
        {hasPinned && (
          <button
            onClick={onClearAll}
            style={{
              fontSize: '12px', border: '1px solid #fecaca', background: '#fef2f2',
              color: '#dc2626', cursor: 'pointer', padding: '3px 10px',
              borderRadius: '4px', fontWeight: 500,
            }}
          >
            Clear All
          </button>
        )}
      </div>
      {terms.map((term) => (
        <div key={term} style={{ marginBottom: '16px' }}>
          <h3 style={{ fontSize: '13px', color: '#888', marginBottom: '8px', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
            {term}
          </h3>
          {ELECTIVE_SETS.filter((s) => s.term === term).map((set) => (
            <ElectiveSet
              key={set.id}
              setId={set.id}
              setName={set.name}
              pinnedCourseId={pinnedCourses[set.id]}
              analysis={treeBySet.get(set.id)}
              loading={treeLoading}
              disabledCourseIds={disabledCourseIds}
              onPin={(courseId) => onPin(set.id, courseId)}
              onUnpin={() => onUnpin(set.id)}
            />
          ))}
        </div>
      ))}
    </div>
  );
}
