import { useEffect, useMemo, useState } from 'react';

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

import { apiClient, getApiErrorMessage } from '../../lib/apiClient';

import { ContextMenu } from '../common/ContextMenu';

import {

  StageModal,

  parseMilestoneLinks,

  type StageFileSavePayload,

  type StageFormData,

} from './StageModal';

import {

  ROUTINE_CATEGORIES,

  getRoutineCategory,

  pickRoutineCategoryTask,

  type RoutineCategory,

} from '../../lib/routineCategories';

import { routineCategoryShellPayload } from '../../lib/taskFormPayload';

import { isRoutineTask } from '../../lib/taskType';

import { getMilestoneSubtitle } from '../../lib/milestoneSubtitle';
import { sortFilesByOrder } from '../../lib/fileDisplay';

import { useTeamMembers } from '../../hooks/useTeamMembers';

import { ResultPreview } from './ResultPreview';

import { MilestoneTimeline, type TimelineViewMode } from './MilestoneTimeline';
import { MilestoneContentList } from './MilestoneContentList';
import { taskTimelineFallback, sortMilestonesForTimeline } from '../../lib/milestoneTimeline';
import { serializePeriodEntries } from '../../lib/milestonePeriods';

import { formatQuarterShort } from '../../lib/boardCalendar';
import { getMilestonePeopleHeaderParts, getTaskPeopleHeaderParts } from '../../lib/teamStatus';

import type { Task, Milestone, FileRecord } from '../../types';



type TaskWithRelations = Task & {

  files: FileRecord[];

  milestones: Milestone[];

};



function LeftSection({ children }: { children: React.ReactNode }) {

  return (

    <section className="flex min-h-0 flex-col overflow-hidden border-b border-[#e8edf2] px-4 py-3 last:border-b-0">

      {children}

    </section>

  );

}



export function RoutineDetailView({
  task: initialTask,
  initialStageId,
}: {
  task: TaskWithRelations;
  initialStageId?: string | null;
}) {

  const qc = useQueryClient();

  const { data: teamMembers = [] } = useTeamMembers();

  const [activeTaskId, setActiveTaskId] = useState(initialTask.id);

  const [selectedStageId, setSelectedStageId] = useState<string | null>(initialStageId ?? null);

  const [stageModal, setStageModal] = useState<{ mode: 'add' | 'edit'; milestone?: Milestone } | null>(null);

  const [stageSaving, setStageSaving] = useState(false);

  const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number; stageId: string } | null>(null);

  const [tabSwitching, setTabSwitching] = useState(false);

  const [timelineView, setTimelineView] = useState<TimelineViewMode>('focus');



  useEffect(() => {

    setActiveTaskId(initialTask.id);

    setTimelineView('focus');

  }, [initialTask.id]);



  useEffect(() => {

    setTimelineView('focus');

  }, [activeTaskId]);



  const { data: activeTask = initialTask } = useQuery({
    queryKey: ['task', activeTaskId],
    queryFn: async () => {
      const { data } = await apiClient.get<TaskWithRelations>(`/tasks/${activeTaskId}`);
      return data;
    },
    initialData: activeTaskId === initialTask.id ? initialTask : undefined,
    staleTime: 10_000,
    retry: 2,
  });

  const { data: quarterTasks = [] } = useQuery({
    queryKey: ['tasks', { quarter: activeTask.quarter }],
    queryFn: async () => {
      const { data } = await apiClient.get<Task[]>('/tasks', {
        params: { quarter: activeTask.quarter },
      });
      return data;
    },
    staleTime: 30_000,
    retry: 2,
  });



  const tabTasks = useMemo(() => {

    const routines = quarterTasks.filter((t) => isRoutineTask(t.taskType));

    return ROUTINE_CATEGORIES.map((label) => ({

      label,

      task: pickRoutineCategoryTask(routines, label),

    }));

  }, [quarterTasks]);



  const activeCategory = getRoutineCategory(activeTask) ?? '채용 운영';



  const handleTabClick = async (label: RoutineCategory, tabTask: Task | null) => {

    if (tabSwitching) return;

    if (tabTask) {

      setActiveTaskId(tabTask.id);

      return;

    }

    setTabSwitching(true);

    try {

      const { data: created } = await apiClient.post<Task>(

        '/tasks',

        routineCategoryShellPayload(label, activeTask.quarter),

      );

      await qc.invalidateQueries({ queryKey: ['tasks'] });

      setActiveTaskId(created.id);

    } catch (err: unknown) {

      alert(getApiErrorMessage(err, `"${label}" 업무를 준비하지 못했습니다.`));

    } finally {

      setTabSwitching(false);

    }

  };



  const milestones = useMemo(

    () => [...(activeTask.milestones ?? [])].sort((a, b) => a.order - b.order),

    [activeTask.milestones],

  );



  useEffect(() => {

    if (initialStageId && milestones.some((m) => m.id === initialStageId)) {

      setSelectedStageId(initialStageId);

    }

  }, [initialTask.id, initialStageId, milestones]);



  useEffect(() => {

    if (!selectedStageId || !milestones.some((m) => m.id === selectedStageId)) {

      setSelectedStageId(milestones[0]?.id ?? null);

    }

  }, [activeTaskId, milestones, selectedStageId]);



  const selectedStage = milestones.find((m) => m.id === selectedStageId) ?? null;

  const headerPeople = useMemo(() => {
    const fromStage = getMilestonePeopleHeaderParts(selectedStage);
    if (fromStage.pmName || fromStage.assigneeNames.length > 0) return fromStage;
    return getTaskPeopleHeaderParts(activeTask);
  }, [selectedStage, activeTask]);

  const headerProgressLabel = useMemo(() => {
    if (selectedStage) return `${selectedStage.progress}%`;
    if (milestones.length === 0) return '—';
    const avg = Math.round(
      milestones.reduce((sum, m) => sum + (m.progress ?? 0), 0) / milestones.length,
    );
    return `${avg}%`;
  }, [selectedStage, milestones]);

  const stageFiles = useMemo(

    () =>

      sortFilesByOrder(

        selectedStageId ? (activeTask.files ?? []).filter((f) => f.milestoneId === selectedStageId) : [],

      ),

    [activeTask.files, selectedStageId],

  );



  const stageLinks = useMemo(

    () => (selectedStage ? parseMilestoneLinks(selectedStage.links) : []),

    [selectedStage],

  );

  const quarterRoutineTasks = useMemo(
    () => quarterTasks.filter((t) => isRoutineTask(t.taskType)),
    [quarterTasks],
  );

  const portfolioTasks = useMemo(
    () =>
      quarterRoutineTasks.map((t) => ({
        id: t.id,
        title: t.title,
        milestones: sortMilestonesForTimeline((t.milestones ?? []) as Milestone[]),
      })),
    [quarterRoutineTasks],
  );

  const showGanttPanel = timelineView !== 'focus';
  const showPortfolioFull = timelineView === 'portfolio';



  const deleteStage = useMutation({

    mutationFn: (id: string) => apiClient.delete(`/milestones/item/${id}`),

    onSuccess: () => qc.invalidateQueries({ queryKey: ['task', activeTaskId] }),

  });



  const uploadFiles = async (milestoneId: string, filePayload: StageFileSavePayload['uploads']) => {

    for (const item of filePayload) {

      const form = new FormData();

      form.append('file', item.file);

      form.append('milestoneId', milestoneId);

      form.append('sortOrder', String(item.sortOrder));

      if (item.displayName.trim()) {

        form.append('displayName', item.displayName.trim());

      }

      await apiClient.post(`/files/upload/${activeTaskId}`, form);

    }

  };



  const handleStageSave = async (data: StageFormData, filePayload: StageFileSavePayload) => {

    setStageSaving(true);

    try {

      const payload = {

        title: data.title.trim(),

        subtitle: data.subtitle.trim() || null,

        periodEntries: serializePeriodEntries(data.periodEntries),

        progress: data.progress,

        links: data.links,

        pmMemberId: data.pmMemberId || null,

        assigneeMemberIds: data.assigneeMemberIds,

      };



      let milestoneId: string;



      if (stageModal?.mode === 'add') {

        const { data: created } = await apiClient.post<Milestone>(

          `/milestones/${activeTaskId}`,

          payload,

        );

        milestoneId = created.id;

        setSelectedStageId(created.id);

      } else if (stageModal?.milestone) {

        const { data: updated } = await apiClient.patch<Milestone>(

          `/milestones/item/${stageModal.milestone.id}`,

          payload,

        );

        milestoneId = updated.id;

        setSelectedStageId(updated.id);

      } else {

        return;

      }



      try {

        for (const id of filePayload.deletedFileIds) {

          await apiClient.delete(`/files/${id}`);

        }

        for (const rep of filePayload.replacements) {

          const form = new FormData();

          form.append('file', rep.file);

          await apiClient.post(`/files/${rep.id}/replace`, form);

        }

        for (const edit of filePayload.existingEdits) {

          const original = activeTask.files?.find((f) => f.id === edit.id);

          if (!original) continue;

          const prevName = (original.displayName ?? '').trim();

          const nextName = edit.displayName.trim();

          const prevOrder = original.sortOrder ?? 0;

          if (nextName !== prevName || edit.sortOrder !== prevOrder) {

            await apiClient.patch(`/files/${edit.id}`, {

              displayName: nextName || null,

              sortOrder: edit.sortOrder,

            });

          }

        }

        if (filePayload.uploads.length > 0) {

          await uploadFiles(milestoneId, filePayload.uploads);

        }

      } catch (err: unknown) {

        alert(`단계는 저장됐지만 ${getApiErrorMessage(err, '파일 처리에 실패했습니다.')}`);

      }



      await qc.invalidateQueries({ queryKey: ['task', activeTaskId] });

      setStageModal(null);

    } catch (err: unknown) {

      alert(getApiErrorMessage(err, '단계 저장에 실패했습니다.'));

    } finally {

      setStageSaving(false);

    }

  };



  return (

    <div className="detail-page-shell flex h-full min-h-0 flex-col overflow-hidden">

      <header className="detail-page-header detail-page-header--routine shrink-0">

        <div className="detail-page-header__tabs">

          {tabTasks.map(({ label, task: tabTask }) => {

            const isActive = activeCategory === label;

            return (

              <button

                key={label}

                type="button"

                disabled={tabSwitching}

                className={`detail-page-header__tab ${isActive ? 'is-active' : ''}`}

                onClick={() => handleTabClick(label, tabTask)}

              >

                {label}

              </button>

            );

          })}

        </div>

        <div className="detail-page-header__meta">
          <span>
            <span className="detail-page-header__meta-label">분기 </span>
            <span className="detail-page-header__meta-value">{formatQuarterShort(activeTask.quarter)}</span>
          </span>
          <span className="detail-page-header__divider" aria-hidden="true" />
          <span>
            <span className="detail-page-header__meta-label">업무 </span>
            <span className="detail-page-header__meta-value">{milestones.length}건</span>
          </span>
          {(headerPeople.pmName || headerPeople.assigneeNames.length > 0) && (
            <>
              <span className="detail-page-header__divider" aria-hidden="true" />
              {headerPeople.pmName && (
                <span>
                  <span className="detail-page-header__meta-label">PM </span>
                  <span className="detail-page-header__meta-value">{headerPeople.pmName}</span>
                </span>
              )}
              {headerPeople.assigneeNames.length > 0 && (
                <span>
                  <span className="detail-page-header__meta-label">담당 </span>
                  <span className="detail-page-header__meta-value">
                    {headerPeople.assigneeNames.join(' · ')}
                  </span>
                </span>
              )}
            </>
          )}
          <span className="detail-page-header__badge">{headerProgressLabel}</span>
        </div>

      </header>



      <div className={`grid min-h-0 flex-1 grid-rows-1 ${showPortfolioFull ? 'detail-page-grid--portfolio' : 'grid-cols-[1fr_3fr]'}`}>

        {!showPortfolioFull && (

        <aside className="detail-aside grid h-full min-h-0 grid-rows-[2fr_1fr] overflow-hidden">

          <LeftSection>

            <div className="detail-section-head">

              <h3 className="detail-section-label">업무명</h3>

              <button

                type="button"

                title="단계 추가"

                onClick={() => setStageModal({ mode: 'add' })}

                className="detail-add-btn"

              >

                +

              </button>

            </div>

            <div className="flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto pr-1">

              {milestones.length === 0 ? (

                <p className="detail-body-muted">+ 버튼으로 단계를 추가하세요.</p>

              ) : (

                milestones.map((stage) => {

                  const isSelected = stage.id === selectedStageId;

                  const subtitle = getMilestoneSubtitle(stage);

                  return (

                    <button

                      key={stage.id}

                      type="button"

                      className={`detail-stage-card shrink-0 rounded-lg border px-3 py-2 text-left transition-colors ${

                        isSelected

                          ? 'is-selected ring-1 ring-[#7eb3e8]'

                          : 'hover:border-slate-300 hover:bg-white/80'

                      }`}

                      onClick={() => setSelectedStageId(stage.id)}

                      onContextMenu={(e) => {

                        e.preventDefault();

                        setSelectedStageId(stage.id);

                        setCtxMenu({ x: e.clientX, y: e.clientY, stageId: stage.id });

                      }}

                    >

                      <p className="detail-body-title truncate">{stage.title}</p>

                      {subtitle ? (
                        <p className="detail-body-caption mt-0.5 truncate">{subtitle}</p>
                      ) : null}

                    </button>

                  );

                })

              )}

            </div>

          </LeftSection>



          <LeftSection>

            <MilestoneContentList
              milestone={selectedStage}
              emptyMessage={
                selectedStage
                  ? '수행 기간에 업무내용을 입력하세요.'
                  : '단계를 선택하세요.'
              }
            />

          </LeftSection>

        </aside>

        )}



        <div className={`detail-main-panel flex h-full min-h-0 min-w-0 flex-col${showGanttPanel ? ' detail-panel--gantt' : ''}${showPortfolioFull ? ' detail-panel--portfolio' : ''}`}>

          {timelineView === 'focus' && (

          <ResultPreview

            files={stageFiles}

            links={stageLinks}

            hasSelectedStage={!!selectedStage}

          />

          )}



          <MilestoneTimeline

            variant="routine"

            milestones={milestones}

            portfolioTasks={portfolioTasks}

            fallback={taskTimelineFallback(activeTask)}

            selectedId={selectedStageId}

            onSelect={setSelectedStageId}

            ownerTaskId={activeTaskId}

            viewMode={timelineView}

            onViewModeChange={setTimelineView}

            emptyMessage="기간을 설정한 업무명만 타임라인에 표시됩니다."

          />

        </div>

      </div>



      {stageModal && (

        <StageModal

          variant="routine"

          mode={stageModal.mode}

          milestone={stageModal.milestone}

          existingFiles={

            stageModal.milestone

              ? sortFilesByOrder(

                  (activeTask.files ?? []).filter((f) => f.milestoneId === stageModal.milestone!.id),

                )

              : []

          }

          teamMembers={teamMembers}

          saving={stageSaving}

          onClose={() => setStageModal(null)}

          onSave={handleStageSave}

        />

      )}



      {ctxMenu && (

        <ContextMenu

          x={ctxMenu.x}

          y={ctxMenu.y}

          onClose={() => setCtxMenu(null)}

          items={[

            {

              icon: '✏',

              label: '수정',

              onClick: () => {

                const m = milestones.find((s) => s.id === ctxMenu.stageId);

                if (m) setStageModal({ mode: 'edit', milestone: m });

              },

            },

            {

              icon: '🗑',

              label: '삭제',

              danger: true,

              onClick: () => {

                if (window.confirm('이 단계를 정말 삭제하시겠습니까?')) {

                  deleteStage.mutate(ctxMenu.stageId);

                }

              },

            },

          ]}

        />

      )}

    </div>

  );

}



export function RoutineDetailShell({
  task,
  initialStageId,
}: {
  task: TaskWithRelations;
  initialStageId?: string | null;
}) {

  return <RoutineDetailView task={task} initialStageId={initialStageId} />;

}

