const { useState, useEffect } = React;

const K3D_STORAGE_KEY = 'k3DirectFilters';

const FormatK3Direct = () => {
  const [students, setStudents] = useState([]);
  const [courses, setCourses] = useState([]);
  const [allCourses, setAllCourses] = useState([]);
  const [exams, setExams] = useState([]);
  const [batches, setBatches] = useState([]);
  const [loading, setLoading] = useState(true);
  
  const [selectedCourse, setSelectedCourse] = useState('');
  const [courseSearchQuery, setCourseSearchQuery] = useState('');
  const [selectedExam, setSelectedExam] = useState('');
  const [selectedBatch, setSelectedBatch] = useState('');
  const [sessionMax, setSessionMax] = useState(25);
  const [totalPracticals, setTotalPracticals] = useState(12);
  
  // Maps student.id -> string input (target average)
  const [targetMarks, setTargetMarks] = useState({});
  const [showCopyModal, setShowCopyModal] = useState(false);
  const [copySourceCourse, setCopySourceCourse] = useState('');
  const [copySourceFormat, setCopySourceFormat] = useState('K3');

  useEffect(() => {
    Promise.all([
      fetch('/api/courses').then(res => res.json()),
      fetch('/api/exams').then(res => res.json()),
      fetch('/api/batches').then(res => res.json())
    ]).then(([courseData, examData, batchData]) => {
      setAllCourses(courseData);
      const filteredCourses = courseData.filter(c => parseFloat(c.fa_pr_max) > 0);
      setCourses(filteredCourses);
      setExams(examData);
      setBatches(batchData);
      const saved = (() => { try { return JSON.parse(localStorage.getItem(K3D_STORAGE_KEY)) || {}; } catch(e) { return {}; } })();
      if (saved.course && filteredCourses.find(c => String(c.id) === String(saved.course))) setSelectedCourse(saved.course);
      else if (filteredCourses.length > 0) setSelectedCourse(filteredCourses[0].id);
      if (saved.exam && examData.find(e => String(e.id) === String(saved.exam))) setSelectedExam(saved.exam);
      else if (examData.length > 0) setSelectedExam(examData[0].id);
      if (saved.batch && batchData.find(b => String(b.id) === String(saved.batch))) setSelectedBatch(saved.batch);
      else if (batchData.length > 0) setSelectedBatch(batchData[0].id);
      setLoading(false);
    }).catch(err => {
      console.error(err);
      setLoading(false);
    });
  }, []);

  // Persist filter selections
  useEffect(() => {
    if (selectedCourse && selectedExam) {
      try { localStorage.setItem(K3D_STORAGE_KEY, JSON.stringify({ course: selectedCourse, exam: selectedExam, batch: selectedBatch })); } catch(e) {}
    }
  }, [selectedCourse, selectedExam, selectedBatch]);

  useEffect(() => {
    if (courses.length > 0) {
      const filtered = courses.filter(c => (c.code + ' ' + c.name).toLowerCase().includes(courseSearchQuery.toLowerCase()));
      if (filtered.length > 0 && !filtered.find(c => String(c.id) === String(selectedCourse))) {
        setSelectedCourse(filtered[0].id);
      }
    }
  }, [courseSearchQuery]);

  // Auto-set sessionMax from course master fa_pr_max
  useEffect(() => {
    if (selectedCourse && courses.length > 0) {
      const course = courses.find(c => String(c.id) === String(selectedCourse));
      if (course && parseFloat(course.fa_pr_max) > 0) {
        setSessionMax(parseFloat(course.fa_pr_max));
      }
    }
  }, [selectedCourse, courses]);

  // Fetch true max practicals based on lab-plans for current course/exam
  useEffect(() => {
    if (!selectedExam || !selectedCourse) return;
    Promise.all([
      fetch(`/api/lab-assessments?exam_id=${selectedExam}&course_id=${selectedCourse}&t=${Date.now()}`).then(res => res.ok ? res.json() : []),
      fetch(`/api/lab-plans?exam_id=${selectedExam}&course_id=${selectedCourse}&t=${Date.now()}`).then(res => res.ok ? res.json() : [])
    ]).then(([allMarksData, plansData]) => {
      let maxPracticalsCalculated = 12;
      const currentCourse = courses.find(c => String(c.id) === String(selectedCourse));
      if (currentCourse && String(currentCourse.code).trim() === '316004') maxPracticalsCalculated = 8;
      
      let maxPlanned = 0;
      if (Array.isArray(plansData)) {
          plansData.forEach(p => { if (p.practical_no > maxPlanned) maxPlanned = p.practical_no; });
      }
      let maxSaved = 0;
      if (Array.isArray(allMarksData)) {
          allMarksData.forEach(m => { if (m.practical_no > maxSaved) maxSaved = m.practical_no; });
      }
      if (maxPlanned > 0 || maxSaved > 0) maxPracticalsCalculated = Math.max(maxPlanned, maxSaved);
      
      if (currentCourse && String(currentCourse.code).trim() === '316004' && maxPracticalsCalculated > 8) {
          maxPracticalsCalculated = 8;
      }
      
      setTotalPracticals(maxPracticalsCalculated);
    }).catch(console.error);
  }, [selectedExam, selectedCourse]);

  // Fetch eligible students and map existing marks
  const fetchData = () => {
    if (!selectedExam || !selectedCourse) return;
    setLoading(true);
    Promise.all([
      fetch(`/api/courses/${selectedCourse}/eligible-students?t=${Date.now()}`).then(res => res.json()),
      fetch(`/api/exams/${selectedExam}/roster?t=${Date.now()}`).then(res => res.json()),
      fetch(`/api/lab-assessments?exam_id=${selectedExam}&course_id=${selectedCourse}&t=${Date.now()}`).then(res => res.json())
    ]).then(([eligibleData, rosterData, marksData]) => {
      const mappedStudents = Array.isArray(eligibleData) ? eligibleData.map(student => {
          const registered = Array.isArray(rosterData) ? rosterData.find(r => r.student_id === student.id) : null;
          return { ...student, seat_number: registered ? registered.seat_number : '' };
      }) : [];
      setStudents(mappedStudents);
      
      const initials = {};
      mappedStudents.forEach(s => { 
           let assignedMarks = [];
           if (Array.isArray(marksData)) {
               assignedMarks = marksData.filter(m => m.student_id === s.id);
           }
           if (assignedMarks.length > 0) {
               let sum = 0;
               assignedMarks.forEach(m => sum += (parseFloat(m.process_marks)||0) + (parseFloat(m.product_marks)||0));
               let avg = Math.round(sum / assignedMarks.length);
               initials[s.id] = String(avg);
           } else {
               initials[s.id] = ''; 
           }
      });
      setTargetMarks(initials);
      
      setLoading(false);
    }).catch(err => {
      console.error(err);
      setLoading(false);
    });
  };

  useEffect(() => {
    fetchData();
  }, [selectedExam, selectedCourse]);

  const handleInputChange = (studentId, value) => {
      let numValue = parseFloat(value);
      if (isNaN(numValue)) numValue = '';
      else {
          if (numValue > sessionMax) numValue = sessionMax;
          if (numValue < 0) numValue = 0;
      }
      setTargetMarks(prev => ({
          ...prev, [studentId]: numValue === '' ? '' : String(numValue)
      }));
  };

  const generateMarks = (targetAverage, count, maxTotal, courseCode) => {
    let T = parseFloat(targetAverage);
    if (isNaN(T) || T <= 0) return new Array(count).fill(0);
    
    let totalSum = Math.round(T * count);
    
    if (totalSum > maxTotal * count) {
        totalSum = maxTotal * count;
    }

    if (courseCode === '316004') {
        let intArr = [];
        let baseVal = Math.floor(totalSum / count);
        let remainder = totalSum % count;
        
        for (let i = 0; i < count; i++) {
            intArr.push(baseVal);
        }
        
        for (let i = 0; i < remainder; i++) {
            intArr[count - 1 - i] += 1;
        }
        
        for (let i = 0; i < intArr.length; i++) {
            if (intArr[i] > maxTotal) intArr[i] = maxTotal;
            if (intArr[i] < 0) intArr[i] = 0;
        }
        
        intArr.sort((a,b) => a-b);
        return intArr;
    }

    let minVal = Math.max(0, T - (0.25 * T));
    let maxVal = Math.min(maxTotal, T + (0.08 * T));
    
    let floatArr = [];
    for(let i=0; i<count; i++) {
         if (count === 1) floatArr.push(T);
         else {
             let t = i / (count - 1);
             floatArr.push(minVal + t * (maxVal - minVal));
         }
    }
    
    let currentFloatSum = floatArr.reduce((a,b)=>a+b, 0);
    let diffFloat = totalSum - currentFloatSum;
    floatArr = floatArr.map(x => x + diffFloat / count);
    
    let intArr = floatArr.map(x => Math.round(x));
    
    if (totalSum > maxTotal * count) {
        totalSum = maxTotal * count;
    }

    for (let i = 0; i < intArr.length; i++) {
        if (intArr[i] > maxTotal) intArr[i] = maxTotal;
        if (intArr[i] < 0) intArr[i] = 0;
    }
    
    let finalSum = intArr.reduce((a,b) => a+b, 0);
    
    let loopGuard = 0;
    while(finalSum < totalSum && loopGuard < 1000) {
       let added = false;
       for(let i=count-1; i>=0; i--) {
          if (intArr[i] < maxTotal) {
              intArr[i]++; finalSum++; added=true; break;
          }
       }
       if (!added) break;
       loopGuard++;
    }
 
    loopGuard = 0;
    while(finalSum > totalSum && loopGuard < 1000) {
       let subtracted = false;
       for(let i=0; i<count; i++) {
          if (intArr[i] > 0) {
              intArr[i]--; finalSum--; subtracted=true; break;
          }
       }
       if (!subtracted) break;
       loopGuard++;
    }
    
    intArr.sort((a,b) => a-b);
    return intArr;
  };

  const handleExecuteDistribution = async () => {
      const activeStudents = students.filter(s => targetMarks[s.id] !== '' && !isNaN(parseFloat(targetMarks[s.id])));
      if (activeStudents.length === 0) {
          return alert("Please enter a target average mark for at least one student.");
      }
      if (!confirm(`Distribute and overwrite K3 marks for ${activeStudents.length} students across ${totalPracticals} practicals?`)) {
          return;
      }

      setLoading(true);
      let allPayloads = [];

      activeStudents.forEach(student => {
          let T = parseFloat(targetMarks[student.id]);
          const currentCourse = courses.find(c => String(c.id) === String(selectedCourse));
          const currentCourseCode = currentCourse ? String(currentCourse.code).trim() : '';
          let sequence = generateMarks(T, totalPracticals, sessionMax, currentCourseCode);

          sequence.forEach((M, index) => {
              let pNo = index + 1;
              allPayloads.push({
                 student_id: student.id,
                 practical_no: pNo,
                 process_marks: M,
                 product_marks: 0
              });
          });
      });

      let successes = 0;
      let errors = 0;

      try {
          const res = await fetch('/api/lab-assessments', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ 
                  exam_id: selectedExam, 
                  course_id: selectedCourse, 
                  session_max_marks: sessionMax, 
                  student_ids: activeStudents.map(s => s.id),
                  marksData: allPayloads.map(p => ({
                      student_id: p.student_id,
                      practical_no: p.practical_no,
                      process_marks: p.process_marks,
                      product_marks: 0
                  }))
              })
          });
          if(res.ok) successes = totalPracticals;
          else errors = 1;
      } catch(e) {
          errors = 1;
          console.error(e);
      }

      setLoading(false);
      alert(`Distribution Complete.\nPracticals Updated: ${successes}\nErrors: ${errors}`);
      fetchData();
  };

  const handleExportDetailedExcel = async () => {
      if (!selectedCourse || !selectedExam) return alert('Select course and exam term first');
      const course = courses.find(c => String(c.id) === String(selectedCourse));
      
      setLoading(true);
      let allMarks = [];
      try {
          const resMarks = await fetch(`/api/lab-assessments?exam_id=${selectedExam}&course_id=${selectedCourse}&t=${Date.now()}`);
          allMarks = await resMarks.json();
      } catch(err) {
          console.error("Failed to fetch cumulative marks for Excel", err);
      }
      setLoading(false);

      const N = totalPracticals;
      const wsData = [];
      
      const header1 = ["Roll No", "Enrollment No", "Name of Student"];
      const header2 = ["", "", ""];
      for (let i = 1; i <= N; i++) {
          header1.push(`Practical ${i}`);
          header2.push(`(Max: ${sessionMax})`);
      }
      header1.push("Overall Sum", "Average");
      header2.push("", "");

      wsData.push(["K3 Auto-Distribute — Detailed Report"]);
      wsData.push([`Course: ${course ? course.code + ' - ' + course.name : selectedCourse}`]);
      wsData.push([]);
      wsData.push(header1);
      wsData.push(header2);

      students.forEach(s => {
          const row = [s.roll_no || '-', s.enrollment_no, s.full_name || s.name];
          let totalSum = 0;
          let assessedCount = 0;
          
          for (let i = 1; i <= N; i++) {
              const markRecord = Array.isArray(allMarks) ? allMarks.find(m => m.student_id === s.id && String(m.practical_no) === String(i)) : null;
              if (markRecord) {
                  const marks = (parseFloat(markRecord.process_marks) || 0) + (parseFloat(markRecord.product_marks) || 0);
                  row.push(marks);
                  totalSum += marks;
                  assessedCount++;
              } else {
                  row.push('-');
              }
          }
          row.push(totalSum > 0 ? totalSum : '-');
          if (totalSum > 0 && assessedCount > 0) {
               row.push(Math.round(totalSum / assessedCount));
          } else {
               row.push('-');
          }
          wsData.push(row);
      });

      const ws = window.XLSX.utils.aoa_to_sheet(wsData);
      const merges = [{s:{r:0, c:0}, e:{r:0, c:10}}];
      ws['!merges'] = merges;
      
      const wb = window.XLSX.utils.book_new();
      window.XLSX.utils.book_append_sheet(wb, ws, `K3_AutoDistribute`);
      window.XLSX.writeFile(wb, `K3_AutoDistribute_${course ? course.code : selectedCourse}.xlsx`);
  };

  const handleCopyExternalMarks = async () => {
       if (!copySourceCourse) return alert("Select source course.");
       setLoading(true);
       try {
           let endpoint = '';

           if (copySourceFormat === 'K3') endpoint = `/api/lab-assessments?exam_id=${selectedExam}&course_id=${copySourceCourse}`;
           else if (copySourceFormat === 'K4') endpoint = `/api/k4-assessments?exam_id=${selectedExam}&course_id=${copySourceCourse}`;
           else if (copySourceFormat === 'K5') endpoint = `/api/theory-assessments?exam_id=${selectedExam}&course_id=${copySourceCourse}`;
           else if (copySourceFormat === 'K6') endpoint = `/api/sla-assessments?exam_id=${selectedExam}&course_id=${copySourceCourse}`;
           
           const res = await fetch(endpoint + '&t=' + Date.now());
           const extMarks = await res.json();
           
           if (!Array.isArray(extMarks) || extMarks.length === 0) {
               alert("No marks found in the source selection.");
               setLoading(false); return;
           }

           const newTargets = { ...targetMarks };
           students.forEach(s => {
               const sMarks = extMarks.filter(m => m.student_id === s.id);
               if (sMarks.length > 0) {
                    if (copySourceFormat === 'K3') {
                         let sum = 0;
                         sMarks.forEach(m => sum += (parseFloat(m.process_marks)||0) + (parseFloat(m.product_marks)||0));
                         newTargets[s.id] = String(Math.round(sum / sMarks.length));
                    } else if (copySourceFormat === 'K4') {
                         const rec = sMarks[0];
                         const sourceC = allCourses.find(c => String(c.id) === String(copySourceCourse));
                         if (rec && rec.marks_obtained !== null && rec.marks_obtained !== undefined) {
                              const obtained = parseFloat(rec.marks_obtained);
                              const max = parseFloat(rec.max_marks) || parseFloat(sourceC?.sa_pr_max) || 0;
                              if (max > 0) newTargets[s.id] = String(Math.round((obtained / max) * sessionMax));
                         }
                    } else if (copySourceFormat === 'K5') {
                         const sourceC = allCourses.find(c => String(c.id) === String(copySourceCourse));
                         let sum = 0; let totalMax = 0; let count = 0;
                         sMarks.forEach(m => {
                             if (m.marks_obtained !== null && m.marks_obtained !== undefined) {
                                 sum += parseFloat(m.marks_obtained) || 0;
                                 totalMax += parseFloat(m.max_marks) || parseFloat(sourceC?.fa_th_max) || 0;
                                 count++;
                             }
                         });
                         if (count > 0 && totalMax > 0) {
                              newTargets[s.id] = String(Math.round((sum / totalMax) * sessionMax));
                         }
                    } else if (copySourceFormat === 'K6') {
                         let sum = 0;
                         sMarks.forEach(m => sum += (parseFloat(m.marks)||0));
                         const sourceC = allCourses.find(c => String(c.id) === String(copySourceCourse));
                         const slaMax = sourceC ? parseFloat(sourceC.sla_max) : 0;
                         if (slaMax > 0) {
                              const scaled = Math.round((sum / slaMax) * sessionMax);
                              newTargets[s.id] = String(Math.min(scaled, sessionMax));
                         }
                    }
               }
           });
           setTargetMarks(newTargets);
           setShowCopyModal(false);
           alert(`External ${copySourceFormat} marks imported and scaled to ${sessionMax}-mark cap!`);
       } catch (err) {
           console.error(err);
           alert("Failed to copy external marks.");
       }
       setLoading(false);
  };
  
  const handleClearAll = () => {
       if(!confirm("Clear all target average marks?")) return;
       const cleared = {...targetMarks};
       students.forEach(s => { cleared[s.id] = ''; });
       setTargetMarks(cleared);
  };

  const handleClearStudent = (studentId) => {
       setTargetMarks(prev => ({ ...prev, [studentId]: '' }));
  };

  if (loading && students.length === 0) return <div className="p-8 text-center text-lg">Loading...</div>;

  return (
    <div className="max-w-7xl mx-auto p-4 sm:p-6 lg:p-8">
      <div className="bg-white rounded-xl shadow-2xl overflow-hidden border border-gray-200">
        <div className="bg-gradient-to-r from-blue-700 to-indigo-800 p-6 text-white text-center shadow-inner relative overflow-hidden">
          <div className="absolute inset-0 bg-black/10"></div>
          <h2 className="text-3xl font-bold tracking-wider relative z-10 drop-shadow-md">Format-K3 Auto Distribute</h2>
          <p className="text-blue-100 text-sm mt-2 font-medium relative z-10">Algorithmic Marks Distribution — Enter target average, get progressive marks across {totalPracticals} practicals</p>
        </div>
        
        <div className="flex flex-col md:flex-row justify-between items-center p-5 bg-gray-50 border-b border-gray-200 gap-5 shadow-sm relative z-20">
          <div className="flex flex-wrap items-center gap-5 text-sm font-semibold text-gray-700">
            <div className="flex flex-col bg-white p-2 rounded border shadow-sm">
              <label className="text-[10px] text-gray-500 uppercase tracking-widest mb-1">Select Term</label>
              <select className="border-none font-bold text-red-800 bg-transparent outline-none cursor-pointer" value={selectedExam} onChange={e => setSelectedExam(e.target.value)}>
                {exams.length === 0 && <option value="">No Terms</option>}
                {exams.map(e => <option key={e.id} value={e.id}>{e.season} {e.year}</option>)}
              </select>
            </div>
            <div className="flex flex-col bg-white p-2 rounded border shadow-sm">
              <label className="text-[10px] text-gray-500 uppercase tracking-widest mb-1">Select Course</label>
              <input 
                 type="text" placeholder="Search Code/Name..." value={courseSearchQuery} onChange={e => setCourseSearchQuery(e.target.value)} 
                 className="w-full border-b border-gray-200 px-1 py-0.5 text-xs bg-white mb-1 focus:border-blue-500 outline-none"
              />
              <select className="border-none font-bold text-blue-900 bg-transparent outline-none cursor-pointer" value={selectedCourse} onChange={e => setSelectedCourse(e.target.value)}>
                {courses.length === 0 && <option value="">No Course</option>}
                {courses.filter(c => (c.code + ' ' + c.name).toLowerCase().includes(courseSearchQuery.toLowerCase())).map(c => <option key={c.id} value={c.id}>{c.code} - {c.name}</option>)}
              </select>
            </div>
          </div>
          
          <div className="flex items-center gap-4 bg-white p-3 rounded-lg border border-gray-200 shadow-md">
             <div>
               <label className="text-[10px] font-bold text-gray-500 uppercase block leading-none mb-1.5">Max / Practical</label>
               <input type="number" className="w-16 border border-gray-300 rounded text-center text-sm px-1 py-1 bg-gray-50 focus:bg-white font-bold" value={sessionMax} onChange={e=>setSessionMax(parseInt(e.target.value)||25)} />
               {(() => { const c = courses.find(x => String(x.id) === String(selectedCourse)); return c && c.fa_pr_min > 0 ? <span className="text-[10px] text-gray-400 font-bold ml-1">Min:{c.fa_pr_min}</span> : null; })()}
             </div>
             <div>
               <label className="text-[10px] font-bold text-purple-600 uppercase block leading-none mb-1.5">N-Practicals</label>
               <input type="number" className="w-16 border border-purple-300 rounded text-center text-sm px-1 py-1 bg-purple-50 text-purple-900 font-bold" value={totalPracticals} onChange={e=>setTotalPracticals(parseInt(e.target.value)||1)} />
             </div>
          </div>
        </div>

        <div className="bg-indigo-50 border-b border-indigo-100 p-4 flex flex-col md:flex-row justify-between items-start md:items-center text-indigo-900 shadow-inner gap-4">
            <div className="text-sm flex-1 w-full md:w-auto">
                <details className="group">
                    <summary className="font-bold mb-1 cursor-pointer select-none flex items-center gap-1 hover:text-indigo-700 w-max">
                        Distribution Rules 
                        <svg className="w-4 h-4 transition-transform group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
                    </summary>
                    <ul className="text-xs space-y-1 list-disc ml-5 w-full max-w-2xl mt-2 pb-2">
                        <li>Sequence generated: <span className="font-bold text-red-600">-25%</span> to <span className="font-bold text-emerald-600">+8%</span> of target average</li>
                        <li>Guaranteed monotonic ascending (scores progressively improve)</li>
                        <li>Max marks ({sessionMax}) limited to at most 20% of practicals</li>
                        <li>Single marks per practical (no process/product split)</li>
                    </ul>
                </details>
            </div>
            <div className="flex flex-wrap gap-2 w-full md:w-auto justify-start md:justify-end">
               <button onClick={() => setShowCopyModal(true)} className="flex-1 md:flex-none items-center justify-center gap-1.5 px-3 sm:px-4 py-2 bg-white border border-purple-200 text-purple-700 hover:bg-purple-600 hover:text-white transition-all shadow-md rounded-lg font-bold text-xs sm:text-sm flex whitespace-nowrap">
                  <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" /></svg>
                  Import Target
               </button>
               <button onClick={handleClearAll} className="flex-1 md:flex-none items-center justify-center gap-1.5 px-3 sm:px-4 py-2 bg-white border border-red-200 text-red-600 hover:bg-red-500 hover:text-white transition-all shadow-md rounded-lg font-bold text-xs sm:text-sm flex whitespace-nowrap">
                  Clear All
               </button>
               <button onClick={handleExportDetailedExcel} className="flex-1 md:flex-none items-center justify-center gap-1.5 px-3 sm:px-4 py-2 bg-white border border-indigo-200 text-indigo-700 hover:bg-indigo-600 hover:text-white transition-all shadow-md rounded-lg font-bold text-xs sm:text-sm flex whitespace-nowrap">
                  Export Report
               </button>
               <button onClick={handleExecuteDistribution} disabled={loading} className="w-full md:w-auto flex items-center justify-center gap-2 px-6 py-2.5 bg-gradient-to-r from-emerald-600 to-green-600 hover:from-emerald-700 hover:to-green-700 transition-all shadow-lg rounded-lg text-white font-bold text-sm md:text-base disabled:opacity-50 whitespace-nowrap">
                  <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
                  Execute Algorithm
               </button>
            </div>
        </div>

        <div className="overflow-x-auto relative min-h-[400px]">
          {loading && <div className="absolute inset-0 bg-white/60 backdrop-blur-[2px] z-30 flex items-center justify-center">
             <div className="bg-white p-4 rounded-xl shadow-xl flex items-center gap-3 border border-blue-100 font-bold text-blue-800">
                <svg className="animate-spin h-6 w-6 text-blue-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
                Processing...
             </div>
          </div>}

          <table className="w-full text-left text-sm text-gray-700 relative z-10">
            <thead className="bg-gray-100 text-gray-600 uppercase font-bold text-[11px] tracking-wider sticky top-0 border-b border-gray-300 shadow-sm">
              <tr>
                <th className="px-5 py-4 border-b text-center">Roll No</th>
                <th className="px-5 py-4 border-b">Enrollment No</th>
                <th className="px-5 py-4 border-b text-center text-emerald-800">Exam Seat No.</th>
                <th className="px-5 py-4 border-b border-r">Student Name</th>
                <th className="px-5 py-4 border-b text-center bg-blue-100/50 text-blue-900 border-l">
                  <span>Target Average<br/><span className="text-[10px] text-blue-600 tracking-normal capitalize font-semibold">(Max {sessionMax})</span></span>
                </th>
                <th className="px-3 py-4 border-b bg-gray-50 text-center text-gray-400">Status</th>
                <th className="px-3 py-4 border-b bg-gray-50 text-center text-gray-400">Clear</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-gray-100">
              {students.map((student) => (
                <tr key={student.id} className="hover:bg-blue-50/30 transition-colors group">
                  <td className="px-5 py-3 text-center text-gray-500">{student.roll_no}</td>
                  <td className="px-5 py-3 font-mono text-gray-500">{student.enrollment_no}</td>
                  <td className="px-5 py-3 font-mono text-center font-bold text-emerald-700 bg-emerald-50/20">{student.seat_number || '-'}</td>
                  <td className="px-5 py-3 font-semibold text-gray-800 border-r group-hover:text-blue-700 transition">
                     {student.full_name || student.name}
                  </td>
                  <td className="px-5 py-2 text-center bg-blue-50/20 border-l">
                    <input 
                       type="number" 
                       value={targetMarks[student.id] ?? ''} 
                       onChange={(e) => handleInputChange(student.id, e.target.value)} 
                       className="w-28 px-3 py-2 border-2 border-blue-200 rounded-lg text-center text-blue-900 font-extrabold text-lg focus:ring-4 outline-none shadow-sm transition transform focus:scale-105 bg-white placeholder-gray-300"
                       placeholder={`e.g. ${Math.floor(sessionMax * 0.8)}`}
                    />
                  </td>
                  <td className="px-3 py-3 text-center bg-gray-50/50 text-[10px] uppercase font-bold tracking-widest text-gray-400">
                     {targetMarks[student.id] ? <span className="text-emerald-500">Ready</span> : 'Pending'}
                  </td>
                  <td className="px-3 py-3 text-center bg-gray-50/50">
                     <button onClick={() => handleClearStudent(student.id)} className="text-red-400 hover:text-red-600 transition" title="Clear Student Mark">
                         <svg className="w-5 h-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
                     </button>
                  </td>
                </tr>
              ))}
              {students.length === 0 && !loading && (
                 <tr>
                    <td colSpan="7" className="py-16 text-center text-gray-500 font-medium">
                       No students found. Check Course Mapping or Exam Roster.
                    </td>
                 </tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      {/* Copy External Marks Modal */}
      {showCopyModal && (
        <div className="fixed inset-0 bg-black/60 backdrop-blur-md flex items-center justify-center z-50 p-4">
          <div className="bg-white rounded-2xl shadow-2xl w-full max-w-lg overflow-hidden animate-fade-in-up border border-gray-200">
             <div className="p-6 bg-gradient-to-r from-purple-800 to-indigo-900 text-white flex justify-between items-center">
                <div>
                   <h3 className="font-bold text-xl tracking-wide">Import Target Base Average</h3>
                   <p className="text-sm text-purple-200 mt-1">Cross-subject dimensional scaling</p>
                </div>
                <button onClick={() => setShowCopyModal(false)} className="text-white hover:text-red-300 font-bold text-2xl transition hover:scale-125">&times;</button>
             </div>
             <div className="p-6 bg-gray-50 flex flex-col gap-5">
                <div>
                  <label className="block text-xs font-bold text-gray-500 uppercase tracking-widest mb-2">Source Course</label>
                  <select className="w-full border-2 border-gray-200 rounded-lg px-4 py-3 font-semibold text-gray-800 focus:border-purple-500 outline-none transition" value={copySourceCourse} onChange={e => setCopySourceCourse(e.target.value)}>
                    <option value="">-- Select Source Subject --</option>
                    {courses.map(c => <option key={c.id} value={c.id}>{c.code} - {c.name}</option>)}
                  </select>
                </div>
                <div>
                  <label className="block text-xs font-bold text-gray-500 uppercase tracking-widest mb-2">Source Format</label>
                  <select className="w-full border-2 border-gray-200 rounded-lg px-4 py-3 font-semibold text-gray-800 focus:border-purple-500 outline-none transition" value={copySourceFormat} onChange={e => setCopySourceFormat(e.target.value)}>
                    <option value="K3">Format K3 (Lab Assessment)</option>
                    <option value="K4">Format K4 (SA-PR)</option>
                    <option value="K5">Format K5 (TH-FA)</option>
                    <option value="K6">Format K6 (SLA)</option>
                  </select>
                  <p className="text-xs text-gray-400 mt-3 flex items-start gap-2 bg-purple-50 p-3 rounded-lg border border-purple-100 italic">
                      <svg className="w-4 h-4 shrink-0 text-purple-500 mt-0.5" fill="currentColor" viewBox="0 0 20 20"><path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" /></svg>
                      Marks will be scaled to fit the {sessionMax}-mark cap per practical.
                  </p>
                </div>
             </div>
             <div className="p-5 bg-white border-t flex justify-end gap-3 shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.05)]">
                <button onClick={() => setShowCopyModal(false)} className="px-6 py-2.5 text-gray-600 bg-white border border-gray-300 rounded-lg font-bold hover:bg-gray-50 transition shadow-sm">Cancel</button>
                <button onClick={handleCopyExternalMarks} className="px-6 py-2.5 bg-purple-600 text-white rounded-lg font-bold hover:bg-purple-700 transition shadow-md flex items-center gap-2">
                   Fetch & Scale Marks
                </button>
             </div>
          </div>
        </div>
      )}
    </div>
  );
};
window.FormatK3Direct = FormatK3Direct;
