/* global React */
/* E-1 Part 2a (§5.10 인터랙션, §5.12 출결 플로우):
 *  시간표 셀 클릭 → 수업 세션 모달.
 *  admin (full) + teacher (mode='teacher' 간소화) 공용.
 *
 *  props:
 *   - session: ClassSession | null   null → 모달 닫힘
 *   - onClose: () => void
 *   - onAttendanceChange: (studentId, newStatus) => void   in-memory 업데이트 콜백
 *   - maskPii: boolean                성명·연락처 마스킹 (기본 false)
 *   - mode: 'admin' | 'teacher'      teacher 는 메모/배경색/마감 UI 축소
 */

(function () {
  const { useEffect, useMemo, useState, useRef } = React;
  /* hotfix28.2: a11y 인프라 — Portal 로 조상 transform/filter 영향 차단 + focus trap. */
  const _smPortal = (window.ReactDOM && window.ReactDOM.createPortal) ? window.ReactDOM.createPortal : null;
  const _smUseFocusTrap = (typeof window.useFocusTrap === 'function')
    ? window.useFocusTrap
    : function _smNoopUseFocusTrap() {};
  let _smIdSeq = 0;

  /* 출결 상태 버튼 정의 (§5.12 v5 영문 enum + 마커) */
  const ATT_BUTTONS = [
    { status: 'present',     marker: '○', label: '출석' },
    { status: 'absent',      marker: '✕', label: '결석' },
    { status: 'late',        marker: '△', label: '지각' },
    { status: 'early_leave', marker: '−', label: '조퇴' },
  ];

  const DAY_KO = ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'];

  function formatSessionDate(isoDate) {
    const d = new Date(isoDate + 'T00:00:00');
    return `${d.getFullYear()}년 ${d.getMonth()+1}월 ${d.getDate()}일 ${DAY_KO[d.getDay()]}`;
  }

  function formatTime(iso) {
    if (!iso) return '';
    const t = iso.split('T')[1];
    return t ? t.slice(0, 5) : '';
  }

  /* 이름 마스킹: 3자 이상 → 첫*끝, 2자 → 첫* */
  function maskName(name) {
    if (!name) return '';
    if (name.length <= 1) return name;
    if (name.length === 2) return name[0] + '*';
    return name[0] + '*' + name.slice(-1);
  }

  function SessionModal({ session, onClose, onAttendanceChange, maskPii = false, mode = 'admin' }) {
    /* hooks 는 early return 이전에 선언 (Rules of Hooks) */
    const [memoDraft, setMemoDraft] = useState('');
    const [, forceTick] = useState(0);   /* attendances in-memory mutation 후 rerender */
    /* hotfix28.2: focus trap target + aria-labelledby 용 id. */
    const _smDialogRef = useRef(null);
    const _smTitleId = useMemo(() => { _smIdSeq += 1; return 'sm-title-' + _smIdSeq; }, []);
    _smUseFocusTrap(_smDialogRef, !!session);

    /* ESC 키 닫기 */
    useEffect(() => {
      if (!session) return;
      const h = (e) => { if (e.key === 'Escape') onClose(); };
      window.addEventListener('keydown', h);
      return () => window.removeEventListener('keydown', h);
    }, [session, onClose]);

    /* CORE #2 hotfix21.4: 모달 열린 동안 body scroll lock — 모달 안 스크롤이 끝까지 가도
     *   바깥 시간표 페이지가 같이 스크롤되는 현상 방지.
     * hotfix21.28: scrollbar 폭만큼 padding-right 로 보상하지 않으면, body overflow:hidden 에
     *   세로 스크롤바가 사라지며 viewport 가시 폭이 늘어남 → grid cell 너비 변화 → TimetableGrid
     *   의 ResizeObserver 가 발화 → 학생 칩 +N 측정이 다시 돌면서 카드 안 이름이 줄어들거나
     *   바뀌어 보이는 현상. */
    useEffect(() => {
      if (!session) return;
      const sbw = window.innerWidth - document.documentElement.clientWidth;
      const origOverflow = document.body.style.overflow;
      const origPadRight = document.body.style.paddingRight;
      document.body.style.overflow = 'hidden';
      if (sbw > 0) document.body.style.paddingRight = sbw + 'px';
      return () => {
        document.body.style.overflow = origOverflow;
        document.body.style.paddingRight = origPadRight;
      };
    }, [session]);

    /* Lucide 아이콘 리렌더 */
    useEffect(() => {
      if (window.lucide) window.lucide.createIcons();
    });

    /* session 초기화 시 memo 드래프트 리셋 */
    useEffect(() => {
      setMemoDraft(session?.memo || '');
    }, [session?.id]);

    const data = useMemo(() => {
      if (!session) return null;
      const cls = window.mockQueries?.getClassById?.(session.class_id);
      const teacher = window.mockQueries?.getTeacherById?.(session.teacher_id);
      const room = window.mockQueries?.getRoomById?.(session.room_id);
      const attendances = window.mockQueries?.getAttendancesBySessionId?.(session.id) || [];
      const studentsFromAtt = attendances.map(a => {
        const st = window.mockQueries?.getStudentById?.(a.student_id);
        return { attendance: a, student: st, _chipKind: null };
      }).filter(x => x.student);
      const seen = new Set(studentsFromAtt.map(x => x.student.id));
      const extras = [];
      /* hotfix21.31: 보충 카드(isMakeup) 는 attendance row 없음 — base enrollment 자동 포함.
         원본 class 의 학생들이 보충 받는 게 기본 의도. attendance 는 fake (Phase 5 후속에서 실 attendance 생성). */
      if (session.isMakeup) {
        const baseEnrolled = window.mockQueries?.getStudentsByClassId?.(session.class_id) || [];
        for (const st of baseEnrolled) {
          if (seen.has(st.id)) continue;
          seen.add(st.id);
          extras.push({
            attendance: { id: 'makeup_base_' + session.id + '_' + st.id, student_id: st.id, status: 'pending' },
            student: st,
            _chipKind: null,
            _virtual: true,
          });
        }
      }
      /* chipOnceAdds / chipMakeupAdds 학생도 명단에 포함 (1회 / 보충 마크). */
      let onceMap = {}, makeupMap = {};
      try { onceMap   = JSON.parse(localStorage.getItem('c200-admin.chipOnceAdds')   || '{}'); } catch (_) {}
      try { makeupMap = JSON.parse(localStorage.getItem('c200-admin.chipMakeupAdds') || '{}'); } catch (_) {}
      const onceIds = onceMap[session.id]   || [];
      const makeupIds = makeupMap[session.id] || [];
      for (const sid of onceIds) {
        if (seen.has(sid)) continue;
        seen.add(sid);
        const st = window.mockQueries?.getStudentById?.(sid);
        if (!st) continue;
        extras.push({
          attendance: { id: 'once_' + session.id + '_' + sid, student_id: sid, status: 'pending' },
          student: st,
          _chipKind: 'this_only',
          _virtual: true,
        });
      }
      for (const sid of makeupIds) {
        if (seen.has(sid)) continue;
        seen.add(sid);
        const st = window.mockQueries?.getStudentById?.(sid);
        if (!st) continue;
        extras.push({
          attendance: { id: 'makeup_' + session.id + '_' + sid, student_id: sid, status: 'makeup_planned' },
          student: st,
          _chipKind: 'makeup',
          _virtual: true,
        });
      }
      return { cls, teacher, room, students: [...studentsFromAtt, ...extras] };
      /* eslint-disable-next-line react-hooks/exhaustive-deps */
    }, [session?.id, session?.status]);

    if (!session || !data) return null;

    const { cls, teacher, room, students } = data;
    const SL = (window.StatusLabels && window.StatusLabels.STUDENT) || {};
    const isCancelledSess = session.status === 'cancelled';

    const handleAttendanceClick = (studentId, newStatus, curAttendance) => {
      if (isCancelledSess) return;
      /* in-memory mutation — 새로고침 시 reset (의도) */
      if (curAttendance) {
        curAttendance.status = newStatus;
        curAttendance.marked_at = new Date().toISOString().slice(0,16);
        curAttendance.marked_by_user_id = session.teacher_id;
      }
      onAttendanceChange && onAttendanceChange(studentId, newStatus);
      forceTick(t => t + 1);
    };

    const handleBackdropClick = (e) => {
      if (e.target.classList.contains('sm-backdrop')) onClose();
    };

    const handleMemoSave = () => {
      window.showToast && window.showToast('Phase 3에서 저장 구현');
    };
    const handleLockAttendance = () => {
      window.showToast && window.showToast('수업 종료 +24시간 자동 마감 (Phase 3 cron)');
    };

    const sessionStart = formatTime(session.start_at);
    const sessionEnd = formatTime(session.end_at);
    const className = cls?.name || '—';
    const teacherName = teacher?.display_name || teacher?.name || '—';
    const roomName = room?.name || '—';
    const sessionDateStr = formatSessionDate(session.session_date);

    /* hotfix28.2: createPortal — body 직접 마운트로 조상 transform 영향 차단. aria-labelledby 추가. */
    const _smTree = (
      <div className="sm-backdrop" onClick={handleBackdropClick}>
        <div className="sm-modal" role="dialog" aria-modal="true" aria-labelledby={_smTitleId} ref={_smDialogRef}>
          <div className="sm-hd">
            <div className="sm-hd-l">
              <h2 className="sm-title" id={_smTitleId}>{className}</h2>
              {session.isMakeup && <span className="sm-pill sm-pill-makeup">보충</span>}
              {isCancelledSess && <span className="sm-pill sm-pill-cancelled">휴강</span>}
            </div>
            <button className="sm-close" onClick={onClose} aria-label="닫기">
              <i data-lucide="x"></i>
            </button>
          </div>

          {/* 6.1 상단 기본정보 */}
          <div className="sm-info">
            <div className="sm-info-row">
              <span className="sm-info-k">강사</span>
              <span className="sm-info-v">{teacherName}</span>
            </div>
            <div className="sm-info-row">
              <span className="sm-info-k">시간</span>
              <span className="sm-info-v num">{sessionStart} ~ {sessionEnd}</span>
            </div>
            <div className="sm-info-row">
              <span className="sm-info-k">강의실</span>
              <span className="sm-info-v">{roomName}</span>
            </div>
            <div className="sm-info-row">
              <span className="sm-info-k">날짜</span>
              <span className="sm-info-v">{sessionDateStr}</span>
            </div>
          </div>

          {/* 6.2 학생 명단 + 출결 체크 */}
          <div className="sm-sec">
            <div className="sm-sec-hd">
              <h3>학생 명단 <span className="sm-sec-count num">({students.length})</span></h3>
              {!isCancelledSess && (
                <span className="sm-sec-hint">출결 버튼 클릭 → 즉시 반영</span>
              )}
            </div>
            {students.length === 0 ? (
              <div className="sm-empty">등록된 학생이 없습니다.</div>
            ) : (
              <ul className="sm-student-list">
                {students.map((row, i) => {
                  const { attendance, student, _chipKind } = row;
                  const dispName = maskPii ? maskName(student.name) : student.name;
                  const curStatus = isCancelledSess ? 'cancelled' : attendance.status;
                  return (
                    <li key={attendance.id} className="sm-student-row">
                      <div className="sm-student-l">
                        <span className="sm-student-no num">{String(i+1).padStart(2,'0')}</span>
                        <span className="sm-student-name">{dispName}</span>
                        <span className="sm-student-grade">{student.grade}</span>
                        <span className={`status-pill ${window.StatusLabels?.pillClass?.(student.status) || 'pill-active'}`}>
                          {SL[student.status] || student.status}
                        </span>
                        {_chipKind === 'this_only' && <span className="sm-pill sm-pill-once">1회</span>}
                        {_chipKind === 'makeup'    && <span className="sm-pill sm-pill-makeup">보충</span>}
                      </div>
                      <div className="sm-att-group">
                        {isCancelledSess ? (
                          <span className="sm-att-cancelled">휴강</span>
                        ) : (
                          ATT_BUTTONS.map(btn => (
                            <button
                              key={btn.status}
                              className={`sm-att-btn ${curStatus === btn.status ? 'on' : ''} sm-att-${btn.status}`}
                              onClick={() => handleAttendanceClick(student.id, btn.status, attendance)}
                              title={btn.label}
                            >
                              <span className="sm-att-mark">{btn.marker}</span>
                              <span className="sm-att-label">{btn.label}</span>
                            </button>
                          ))
                        )}
                      </div>
                    </li>
                  );
                })}
              </ul>
            )}
          </div>

          {/* 6.3 메모 · 마감 (Part 2b §1.2 v6 — 배경색 피커 폐기).
               Teacher 모드(mode='teacher'): "출결 마감" 버튼 숨김 — Branch Admin 승인 플로우. */}
          <div className="sm-sec sm-sec-placeholder">
            <div className="sm-sec-hd">
              <h3>메모 · 마감</h3>
            </div>
            <textarea
              className="sm-memo"
              placeholder="수업 메모를 입력하세요 (Phase 3 저장)"
              value={memoDraft}
              onChange={e => setMemoDraft(e.target.value)}
              rows={2}
            />
            <div className="sm-placeholder-row">
              <button className="sm-ph-btn" onClick={handleMemoSave}>
                <i data-lucide="save"></i>메모 저장
              </button>
              {mode !== 'teacher' && (
                <button className="sm-ph-btn sm-ph-lock" onClick={handleLockAttendance}>
                  <i data-lucide="lock"></i>출결 마감
                </button>
              )}
            </div>
          </div>

          {/* 하단 액션 */}
          <div className="sm-ft">
            <span className="sm-ft-note">* Phase 3에서 영구 저장 구현</span>
            <button className="sm-btn-close" onClick={onClose}>닫기</button>
          </div>
        </div>
      </div>
    );
    return _smPortal ? _smPortal(_smTree, document.body) : _smTree;
  }

  window.SessionModal = SessionModal;
})();
