import { appendClientIdHeader } from '../../app/main/clientIdentity';
import { normalizeAutomationTypeId } from '../../app/main/automationTypeAccess';
import { getRegisteredAccessToken } from '../../app/main/tokenAccess';
import type {
  PlanActionType,
  PlanAutomationType,
  PlanActionHistory,
  PlanAutomationUsageSnapshot,
  PlanDraft,
  PlanFilterStatus,
  PlanIssueHistory,
  PlanItem,
  PlanReleaseReview,
  PlanReleaseReviewBoardItem,
  PlanReleaseReviewMetadata,
  PlanReleaseReviewStatus,
  PlanSourceWorkHistory,
} from './types';

function resolvePlanApiBaseUrl() {
  if (import.meta.env.VITE_WORK_SERVER_URL) {
    return import.meta.env.VITE_WORK_SERVER_URL;
  }

  return '/api';
}

function normalizePlanAutomationType(value: unknown): PlanAutomationType {
  return normalizeAutomationTypeId(value);
}

function resolveWorkServerFallbackBaseUrl() {
  if (typeof window === 'undefined') {
    return null;
  }

  const hostname = window.location.hostname;
  const isLocalWorkServerHost =
    hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '0.0.0.0';

  if (!isLocalWorkServerHost) {
    return null;
  }

  const fallbackUrl = new URL(window.location.origin);
  fallbackUrl.port = '3100';
  fallbackUrl.pathname = '/api';
  fallbackUrl.search = '';
  fallbackUrl.hash = '';

  return fallbackUrl.toString().replace(/\/+$/, '');
}

const PLAN_API_BASE_URL = resolvePlanApiBaseUrl();
const PLAN_API_FALLBACK_BASE_URL =
  !import.meta.env.VITE_WORK_SERVER_URL && PLAN_API_BASE_URL === '/api'
    ? resolveWorkServerFallbackBaseUrl()
    : null;

class PlanApiError extends Error {
  status: number;

  constructor(message: string, status: number) {
    super(message);
    this.name = 'PlanApiError';
    this.status = status;
  }
}

export type PlanApiRequestMeta = {
  durationMs: number;
  responseBytes: number;
};

async function requestOnce<T>(baseUrl: string, path: string, init?: RequestInit): Promise<T> {
  const headers = appendClientIdHeader(init?.headers);
  const hasBody = init?.body !== undefined && init.body !== null;
  const method = init?.method?.toUpperCase() ?? 'GET';
  const timeoutMs = 8000;
  const controller = new AbortController();
  const timeoutId = setTimeout(() => {
    controller.abort();
  }, timeoutMs);

  if (hasBody && !headers.has('Content-Type')) {
    headers.set('Content-Type', 'application/json');
  }

  const token = getRegisteredAccessToken();
  if (token && !headers.has('X-Access-Token')) {
    headers.set('X-Access-Token', token);
  }

  let response: Response;

  try {
    response = await fetch(`${baseUrl}${path}`, {
      ...init,
      headers,
      signal: controller.signal,
      cache: init?.cache ?? (method === 'GET' ? 'no-store' : undefined),
    });
  } catch (error) {
    clearTimeout(timeoutId);
    if (error instanceof DOMException && error.name === 'AbortError') {
      throw new PlanApiError('서버 응답이 지연됩니다. 잠시 후 다시 시도해 주세요.', 408);
    }
    throw error;
  }

  clearTimeout(timeoutId);

  if (!response.ok) {
    const text = await response.text();

    try {
      const payload = JSON.parse(text) as { message?: string };
      throw new PlanApiError(payload.message || "요청 처리에 실패했습니다.", response.status);
    } catch {
      throw new PlanApiError(text || "요청 처리에 실패했습니다.", response.status);
    }
  }

  const contentType = response.headers.get("content-type") ?? "";

  if (!contentType.toLowerCase().includes("application/json")) {
    const text = await response.text();
    throw new PlanApiError(text ? "서버 응답이 JSON이 아닙니다." : "서버 응답을 확인할 수 없습니다.", 502);
  }

  return response.json() as Promise<T>;
}

async function request<T>(path: string, init?: RequestInit): Promise<T> {
  try {
    return await requestOnce<T>(PLAN_API_BASE_URL, path, init);
  } catch (error) {
    const shouldRetryWithFallback =
      PLAN_API_FALLBACK_BASE_URL &&
      PLAN_API_FALLBACK_BASE_URL !== PLAN_API_BASE_URL &&
      (error instanceof PlanApiError
        ? error.status === 404 || error.status === 408 || error.status === 502
        : error instanceof Error && (/not found/i.test(error.message) || /404/.test(error.message)));

    if (!shouldRetryWithFallback) {
      throw error;
    }

    return requestOnce<T>(PLAN_API_FALLBACK_BASE_URL, path, init);
  }
}

async function requestWithMetaOnce<T>(baseUrl: string, path: string, init?: RequestInit) {
  const headers = appendClientIdHeader(init?.headers);
  const hasBody = init?.body !== undefined && init.body !== null;
  const method = init?.method?.toUpperCase() ?? 'GET';
  const timeoutMs = 8000;
  const controller = new AbortController();
  const timeoutId = setTimeout(() => {
    controller.abort();
  }, timeoutMs);

  if (hasBody && !headers.has('Content-Type')) {
    headers.set('Content-Type', 'application/json');
  }

  const token = getRegisteredAccessToken();
  if (token && !headers.has('X-Access-Token')) {
    headers.set('X-Access-Token', token);
  }

  const startedAt = performance.now();
  let response: Response;

  try {
    response = await fetch(`${baseUrl}${path}`, {
      ...init,
      headers,
      signal: controller.signal,
      cache: init?.cache ?? (method === 'GET' ? 'no-store' : undefined),
    });
  } catch (error) {
    clearTimeout(timeoutId);
    if (error instanceof DOMException && error.name === 'AbortError') {
      throw new PlanApiError('서버 응답이 지연됩니다. 잠시 후 다시 시도해 주세요.', 408);
    }
    throw error;
  }

  clearTimeout(timeoutId);

  const text = await response.text();
  const meta: PlanApiRequestMeta = {
    durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
    responseBytes: new TextEncoder().encode(text).length,
  };

  if (!response.ok) {
    try {
      const payload = JSON.parse(text) as { message?: string };
      throw new PlanApiError(payload.message || '요청 처리에 실패했습니다.', response.status);
    } catch {
      throw new PlanApiError(text || '요청 처리에 실패했습니다.', response.status);
    }
  }

  const contentType = response.headers.get('content-type') ?? '';

  if (!contentType.toLowerCase().includes('application/json')) {
    throw new PlanApiError(text ? '서버 응답이 JSON이 아닙니다.' : '서버 응답을 확인할 수 없습니다.', 502);
  }

  return {
    data: JSON.parse(text) as T,
    meta,
  };
}

async function requestWithMeta<T>(path: string, init?: RequestInit) {
  try {
    return await requestWithMetaOnce<T>(PLAN_API_BASE_URL, path, init);
  } catch (error) {
    const shouldRetryWithFallback =
      PLAN_API_FALLBACK_BASE_URL &&
      PLAN_API_FALLBACK_BASE_URL !== PLAN_API_BASE_URL &&
      (error instanceof PlanApiError
        ? error.status === 404 || error.status === 408 || error.status === 502
        : error instanceof Error && (/not found/i.test(error.message) || /404/.test(error.message)));

    if (!shouldRetryWithFallback) {
      throw error;
    }

    return requestWithMetaOnce<T>(PLAN_API_FALLBACK_BASE_URL, path, init);
  }
}

export async function setupPlanBoard() {
  return request<{ ok: boolean; table: string }>('/plan/setup', {
    method: 'POST',
    body: JSON.stringify({}),
  });
}

export async function fetchPlanItems(status: PlanFilterStatus) {
  void status;
  const query = '';
  const response = await request<{ items: PlanItem[] }>(`/plan/items${query}`);

  return response.items.map(normalizePlanItem);
}

export async function fetchPlanItemsWithLatestSourceWorks(status: PlanFilterStatus) {
  void status;
  const query = '';
  const response = await requestWithMeta<{
    items: PlanItem[];
  }>(`/plan/items${query}`);

  return {
    items: response.data.items.map(normalizePlanItem),
    meta: response.meta,
  };
}

export async function createPlanItem(draft: PlanDraft) {
  const response = await request<{ ok: boolean; item: PlanItem }>('/plan/items', {
    method: 'POST',
    body: JSON.stringify({
      workId: draft.workId,
      note: draft.note,
      automationType: draft.automationType,
      automationContextIds: draft.automationContextIds,
      jangsingProcessingRequired: draft.jangsingProcessingRequired,
      autoDeployToMain: draft.autoDeployToMain,
      suppressWebPush: draft.suppressWebPush,
    }),
  });

  return normalizePlanItem(response.item);
}

export async function updatePlanItem(draft: PlanDraft) {
  if (!draft.id) {
    throw new Error('수정할 작업 항목 ID가 없습니다.');
  }

  const response = await request<{ ok: boolean; item: PlanItem }>(`/plan/items/${draft.id}`, {
    method: 'PATCH',
    body: JSON.stringify({
      workId: draft.workId,
      note: draft.note,
      automationType: draft.automationType,
      automationContextIds: draft.automationContextIds,
      jangsingProcessingRequired: draft.jangsingProcessingRequired,
      autoDeployToMain: draft.autoDeployToMain,
      suppressWebPush: draft.suppressWebPush,
    }),
  });

  return normalizePlanItem(response.item);
}

export async function updatePlanItemJangsingProcessingRequired(id: number, jangsingProcessingRequired: boolean) {
  const response = await request<{ ok: boolean; item: PlanItem }>(`/plan/items/${id}`, {
    method: 'PATCH',
    body: JSON.stringify({
      jangsingProcessingRequired,
    }),
  });

  return normalizePlanItem(response.item);
}

export async function deletePlanItem(id: number) {
  const response = await request<{ ok: boolean; id: number }>(`/plan/items/${id}`, {
    method: 'DELETE',
  });

  return response.id;
}

export async function runPlanAction(id: number, action: PlanActionType) {
  const response = await request<{ ok: boolean; item: PlanItem; message?: string }>(`/plan/items/${id}/actions/${action}`, {
    method: 'POST',
    body: JSON.stringify({}),
  });

  return {
    item: normalizePlanItem(response.item),
    message: response.message,
  };
}

export async function fetchPlanIssueHistories(id: number) {
  const response = await request<{ items: PlanIssueHistory[] }>(`/plan/items/${id}/issues`);
  return response.items;
}

export async function appendPlanIssueAction(id: number, actionNote: string, resolve = false, retry = false) {
  const response = await request<{ ok: boolean; item: PlanIssueHistory; planItem?: PlanItem; message?: string }>(
    `/plan/items/${id}/issues/action`,
    {
      method: 'POST',
      body: JSON.stringify({
        actionNote,
        resolve,
        retry,
      }),
    },
  );

  return {
    item: response.item,
    planItem: response.planItem ? normalizePlanItem(response.planItem) : undefined,
    message: response.message,
  };
}

export async function fetchPlanActionHistories(id: number) {
  const response = await request<{ items: PlanActionHistory[] }>(`/plan/items/${id}/actions`);
  return response.items;
}

export async function appendPlanActionHistory(id: number, actionNote: string) {
  const response = await request<{ ok: boolean; item: PlanActionHistory; planItem?: PlanItem; message?: string }>(
    `/plan/items/${id}/actions/note`,
    {
      method: 'POST',
      body: JSON.stringify({
        actionNote,
        actionType: '추가조치',
      }),
    },
  );

  return {
    item: response.item,
    planItem: response.planItem ? normalizePlanItem(response.planItem) : undefined,
    message: response.message,
  };
}

function normalizePlanItem(item: PlanItem): PlanItem {
  return {
    ...item,
    automationType: normalizePlanAutomationType(item.automationType),
    automationBehaviorType: normalizeAutomationTypeId(item.automationBehaviorType),
    automationContextIds: Array.isArray(item.automationContextIds)
      ? item.automationContextIds.map((value) => String(value).trim()).filter(Boolean)
      : [],
    releaseReviewNote: typeof item.releaseReviewNote === 'string' ? item.releaseReviewNote : '',
    usageSnapshot: normalizePlanAutomationUsageSnapshot(item.usageSnapshot),
  };
}

function normalizePlanAutomationUsageSnapshot(value: PlanAutomationUsageSnapshot | null | undefined) {
  if (!value) {
    return null;
  }

  return {
    tokenTotals: {
      total: Number(value.tokenTotals?.total ?? 0),
      input: Number(value.tokenTotals?.input ?? 0),
      output: Number(value.tokenTotals?.output ?? 0),
      cached: Number(value.tokenTotals?.cached ?? 0),
      reasoning: Number(value.tokenTotals?.reasoning ?? 0),
    },
    totalTokens: Number(value.totalTokens ?? 0),
    retryCount: Number(value.retryCount ?? 0),
    sourceWorkCount: Number(value.sourceWorkCount ?? 0),
    processingStartedAt: value.processingStartedAt ?? null,
    processingEndedAt: value.processingEndedAt ?? null,
    processingEndedAtSource: value.processingEndedAtSource ?? null,
    processingDurationSeconds:
      value.processingDurationSeconds === null || value.processingDurationSeconds === undefined
        ? null
        : Number(value.processingDurationSeconds),
  } satisfies PlanAutomationUsageSnapshot;
}

function normalizePlanScheduledTaskDateRanges(value: unknown): PlanScheduledTaskDateRange[] {
  if (!Array.isArray(value)) {
    return [];
  }

  return value
    .map((item) => ({
      startDate: typeof item?.startDate === 'string' ? item.startDate.trim() : '',
      endDate: typeof item?.endDate === 'string' ? item.endDate.trim() : '',
    }))
    .filter((item) => item.startDate && item.endDate);
}

function normalizePlanScheduledTaskWeekdays(value: unknown): number[] {
  if (!Array.isArray(value)) {
    return [];
  }

  return Array.from(
    new Set(
      value
        .map((item) => Number(item))
        .filter((item) => Number.isInteger(item) && item >= 0 && item <= 6),
    ),
  ).sort((left, right) => left - right);
}

function normalizePlanScheduledTaskTimeWindows(value: unknown): PlanScheduledTaskTimeWindow[] {
  if (!Array.isArray(value)) {
    return [];
  }

  return value
    .map((item) => ({
      startTime:
        typeof item?.startTime === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(item.startTime.trim())
          ? item.startTime.trim()
          : null,
      endTime:
        typeof item?.endTime === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(item.endTime.trim())
          ? item.endTime.trim()
          : null,
    }))
    .filter((item) => item.startTime || item.endTime);
}

export async function fetchPlanSourceWorkHistories(id: number) {
  const response = await request<{ items: PlanSourceWorkHistory[] }>(`/plan/items/${id}/source-works`);
  return response.items;
}

export async function fetchReleaseReviewBoardItems() {
  const response = await request<{ items: PlanReleaseReviewBoardItem[] }>('/plan/release-reviews');
  return response.items;
}

export async function updatePlanReleaseReview(
  planItemId: number,
  payload: {
    status?: PlanReleaseReviewStatus;
    reviewNote?: string;
    metadata?: PlanReleaseReviewMetadata;
  },
) {
  const response = await request<{ ok: boolean; item: PlanReleaseReview }>(`/plan/release-reviews/${planItemId}`, {
    method: 'PATCH',
    body: JSON.stringify(payload),
  });

  return response.item;
}

export async function fetchPlanSourceWorkHistory(id: number, sourceWorkId: number) {
  const response = await request<{ item: PlanSourceWorkHistory }>(
    `/plan/items/${id}/source-works/${sourceWorkId}`,
  );
  return response.item;
}

export type PlanScheduledTask = {
  id: number;
  workId: string;
  note: string;
  automationType: PlanAutomationType;
  automationContextIds: string[];
  releaseTarget: string;
  jangsingProcessingRequired: boolean;
  autoDeployToMain: boolean;
  suppressWebPush: boolean;
  enabled: boolean;
  immediateRunEnabled: boolean;
  refreshContextSnapshotOnNextRun: boolean;
  executionMode: PlanScheduleExecutionMode;
  managedServiceKey: string | null;
  managedServicePackageName: string | null;
  managedServiceDirectory: string | null;
  managedServiceManifestPath: string | null;
  managedServiceGeneratedAt: string | null;
  recreateManagedServiceOnNextSave: boolean;
  scheduleMode: PlanScheduleMode;
  repeatIntervalValue: number;
  repeatIntervalUnit: PlanScheduleRepeatUnit;
  repeatIntervalSeconds: number;
  repeatIntervalMinutes: number;
  dailyRunTime: string;
  scheduleWeekdays: number[];
  scheduleDateRanges: PlanScheduledTaskDateRange[];
  repeatWindows: PlanScheduledTaskTimeWindow[];
  repeatWindowStartTime: string | null;
  repeatWindowEndTime: string | null;
  lastRegisteredAt: string | null;
  createdAt: string;
  updatedAt: string;
};

export type PlanScheduledTaskDateRange = {
  startDate: string;
  endDate: string;
};

export type PlanScheduledTaskTimeWindow = {
  startTime: string | null;
  endTime: string | null;
};

export type PlanScheduleExecutionMode = 'codex' | 'managed-service';
export type PlanScheduleMode = 'interval' | 'daily';
export type PlanScheduleRepeatUnit = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month';

export type PlanScheduledTaskDraft = {
  id: number | null;
  workId: string;
  note: string;
  automationType: PlanAutomationType;
  automationContextIds: string[];
  releaseTarget: string;
  jangsingProcessingRequired: boolean;
  autoDeployToMain: boolean;
  suppressWebPush: boolean;
  enabled: boolean;
  immediateRunEnabled: boolean;
  refreshContextSnapshotOnNextRun: boolean;
  executionMode: PlanScheduleExecutionMode;
  recreateManagedServiceOnNextSave: boolean;
  scheduleMode: PlanScheduleMode;
  repeatIntervalValue: number;
  repeatIntervalUnit: PlanScheduleRepeatUnit;
  repeatIntervalSeconds: number;
  repeatIntervalMinutes: number;
  dailyRunTime: string;
  scheduleWeekdays: number[];
  scheduleDateRanges: PlanScheduledTaskDateRange[];
  repeatWindows: PlanScheduledTaskTimeWindow[];
  repeatWindowStartTime: string | null;
  repeatWindowEndTime: string | null;
};

export type PlanScheduledTaskSaveResult = {
  item: PlanScheduledTask;
  registeredPlan: PlanItem | null;
  registeredBoardPosts: Array<{ id: number } & Record<string, unknown>>;
};

async function requestPlanScheduleTask<T>(pathSuffix = '', init?: RequestInit) {
  const paths = [
    `/plan/scheduled-tasks${pathSuffix}`,
    `/plan/schedule/tasks${pathSuffix}`,
    `/plan/schedule${pathSuffix}`,
    `/plan/schedules${pathSuffix}`,
    `/plans/scheduled-tasks${pathSuffix}`,
    `/plans/schedule/tasks${pathSuffix}`,
    `/plans/schedule${pathSuffix}`,
    `/plans/schedules${pathSuffix}`,
  ];

  let lastNotFoundError: PlanApiError | null = null;

  for (const path of paths) {
    try {
      return await request<T>(path, init);
    } catch (error) {
      if (error instanceof PlanApiError && error.status === 404) {
        lastNotFoundError = error;
        continue;
      }

      throw error;
    }
  }

  throw lastNotFoundError ?? new PlanApiError('스케줄 API 경로를 찾을 수 없습니다.', 404);
}

export async function fetchPlanScheduledTasks() {
  const response = await requestPlanScheduleTask<{ items: PlanScheduledTask[] }>();
  return response.items.map((item) => ({
    ...item,
    automationType: normalizePlanAutomationType(item.automationType),
    automationContextIds: Array.isArray(item.automationContextIds)
      ? item.automationContextIds.map((value) => String(value).trim()).filter(Boolean)
      : [],
    scheduleWeekdays: normalizePlanScheduledTaskWeekdays(item.scheduleWeekdays),
    scheduleDateRanges: normalizePlanScheduledTaskDateRanges(item.scheduleDateRanges),
    repeatWindows: normalizePlanScheduledTaskTimeWindows(item.repeatWindows),
    refreshContextSnapshotOnNextRun: Boolean(item.refreshContextSnapshotOnNextRun),
    recreateManagedServiceOnNextSave: Boolean(item.recreateManagedServiceOnNextSave),
  }));
}

export async function createPlanScheduledTask(draft: PlanScheduledTaskDraft) {
  const response = await requestPlanScheduleTask<{
    ok: boolean;
    item: PlanScheduledTask;
    registeredPlan: PlanItem | null;
    registeredBoardPosts: Array<{ id: number } & Record<string, unknown>>;
  }>('', {
    method: 'POST',
    body: JSON.stringify({
      workId: draft.workId,
      note: draft.note,
      automationType: draft.automationType,
      automationContextIds: draft.automationContextIds,
      releaseTarget: draft.releaseTarget,
      jangsingProcessingRequired: draft.jangsingProcessingRequired,
      autoDeployToMain: draft.autoDeployToMain,
      suppressWebPush: draft.suppressWebPush,
      enabled: draft.enabled,
      immediateRunEnabled: draft.immediateRunEnabled,
      refreshContextSnapshotOnNextRun: draft.refreshContextSnapshotOnNextRun,
      executionMode: draft.executionMode,
      recreateManagedServiceOnNextSave: draft.recreateManagedServiceOnNextSave,
      scheduleMode: draft.scheduleMode,
      repeatIntervalValue: draft.repeatIntervalValue,
      repeatIntervalUnit: draft.repeatIntervalUnit,
      repeatIntervalSeconds: draft.repeatIntervalSeconds,
      repeatIntervalMinutes: draft.repeatIntervalMinutes,
      dailyRunTime: draft.dailyRunTime,
      scheduleWeekdays: draft.scheduleWeekdays,
      scheduleDateRanges: draft.scheduleDateRanges,
      repeatWindows: draft.repeatWindows,
      repeatWindowStartTime: draft.repeatWindowStartTime,
      repeatWindowEndTime: draft.repeatWindowEndTime,
    }),
  });

  return {
    item: {
      ...response.item,
      automationType: normalizePlanAutomationType(response.item.automationType),
      automationContextIds: Array.isArray(response.item.automationContextIds)
        ? response.item.automationContextIds.map((value) => String(value).trim()).filter(Boolean)
        : [],
      scheduleWeekdays: normalizePlanScheduledTaskWeekdays(response.item.scheduleWeekdays),
      scheduleDateRanges: normalizePlanScheduledTaskDateRanges(response.item.scheduleDateRanges),
      repeatWindows: normalizePlanScheduledTaskTimeWindows(response.item.repeatWindows),
      refreshContextSnapshotOnNextRun: Boolean(response.item.refreshContextSnapshotOnNextRun),
      recreateManagedServiceOnNextSave: Boolean(response.item.recreateManagedServiceOnNextSave),
    },
    registeredPlan: response.registeredPlan,
    registeredBoardPosts: Array.isArray(response.registeredBoardPosts) ? response.registeredBoardPosts : [],
  } satisfies PlanScheduledTaskSaveResult;
}

export async function updatePlanScheduledTask(draft: PlanScheduledTaskDraft) {
  if (!draft.id) {
    throw new Error('수정할 스케줄 ID가 없습니다.');
  }

  const response = await requestPlanScheduleTask<{
    ok: boolean;
    item: PlanScheduledTask;
    registeredPlan: PlanItem | null;
    registeredBoardPosts: Array<{ id: number } & Record<string, unknown>>;
  }>(`/${draft.id}`, {
    method: 'PATCH',
    body: JSON.stringify({
      workId: draft.workId,
      note: draft.note,
      automationType: draft.automationType,
      automationContextIds: draft.automationContextIds,
      releaseTarget: draft.releaseTarget,
      jangsingProcessingRequired: draft.jangsingProcessingRequired,
      autoDeployToMain: draft.autoDeployToMain,
      suppressWebPush: draft.suppressWebPush,
      enabled: draft.enabled,
      immediateRunEnabled: draft.immediateRunEnabled,
      refreshContextSnapshotOnNextRun: draft.refreshContextSnapshotOnNextRun,
      executionMode: draft.executionMode,
      recreateManagedServiceOnNextSave: draft.recreateManagedServiceOnNextSave,
      scheduleMode: draft.scheduleMode,
      repeatIntervalValue: draft.repeatIntervalValue,
      repeatIntervalUnit: draft.repeatIntervalUnit,
      repeatIntervalSeconds: draft.repeatIntervalSeconds,
      repeatIntervalMinutes: draft.repeatIntervalMinutes,
      dailyRunTime: draft.dailyRunTime,
      scheduleWeekdays: draft.scheduleWeekdays,
      scheduleDateRanges: draft.scheduleDateRanges,
      repeatWindows: draft.repeatWindows,
      repeatWindowStartTime: draft.repeatWindowStartTime,
      repeatWindowEndTime: draft.repeatWindowEndTime,
    }),
  });

  return {
    item: {
      ...response.item,
      automationType: normalizePlanAutomationType(response.item.automationType),
      automationContextIds: Array.isArray(response.item.automationContextIds)
        ? response.item.automationContextIds.map((value) => String(value).trim()).filter(Boolean)
        : [],
      scheduleWeekdays: normalizePlanScheduledTaskWeekdays(response.item.scheduleWeekdays),
      scheduleDateRanges: normalizePlanScheduledTaskDateRanges(response.item.scheduleDateRanges),
      repeatWindows: normalizePlanScheduledTaskTimeWindows(response.item.repeatWindows),
      refreshContextSnapshotOnNextRun: Boolean(response.item.refreshContextSnapshotOnNextRun),
      recreateManagedServiceOnNextSave: Boolean(response.item.recreateManagedServiceOnNextSave),
    },
    registeredPlan: response.registeredPlan,
    registeredBoardPosts: Array.isArray(response.registeredBoardPosts) ? response.registeredBoardPosts : [],
  } satisfies PlanScheduledTaskSaveResult;
}

export async function deletePlanScheduledTask(id: number) {
  const response = await requestPlanScheduleTask<{ ok: boolean; id: number }>(`/${id}`, {
    method: 'DELETE',
  });

  return response.id;
}
