import { appendClientIdHeader } from '../../../../app/main/clientIdentity';
import { getRegisteredAccessToken } from '../../../../app/main/tokenAccess';

const WORK_SERVER_TIMEOUT_MS = 15_000;
const BASEBALL_TICKET_BAY_RUN_TIMEOUT_MS = 180_000;
let baseballTicketBayShareTokenOverride = '';

export type BaseballTicketBayTimeWindow = {
  id: string;
  start: string;
  end: string;
};

export type BaseballTicketBayAlertItem = {
  id: string;
  clientId: string;
  ownerType: 'client' | 'shared-token';
  ownerId: string;
  ownerLabel?: string | null;
  title: string;
  eventDate: string;
  team: string;
  zone: string;
  aisleSide: string;
  seatDirections: string[];
  maxPrice: number | null;
  seatCount: number;
  batchIntervalMinutes: number;
  sameProductAlertEnabled: boolean;
  sameProductNotifyOnce: boolean;
  active: boolean;
  timeWindows: BaseballTicketBayTimeWindow[];
  createdAt: string;
  updatedAt: string;
  lastRunAt: string | null;
  lastMatchAt: string | null;
};

export type BaseballTicketBayMatchResult = {
  productId: number;
  displayNumber: string;
  saleUrl: string;
  title: string;
  eventDateTime: string;
  categoryName: string;
  teamName: string;
  area: string;
  rowLabel: string;
  row: string;
  opponentOrFloor: string;
  grade: string;
  addInfo: string;
  seatCount: number | null;
  together: boolean;
  price: number | null;
  totalPrice: number | null;
  transactionType: string;
  sellerPost: string;
  productRemarks: string[];
  seatRemarks: string[];
  seatMapImageUrl: string | null;
  photoUrls: string[];
  sellerPhotoCount: number;
  createdAt: string;
  safeTrade: boolean;
  pinTrade: boolean;
  deliveryTrade: boolean;
  fieldTrade: boolean;
  etcTrade: boolean;
};

export type BaseballTicketBayRunPayload = {
  keyword: string;
  scannedCategoryCount: number;
  scannedItemTotalCount?: number;
  scannedCategories: Array<{
    categoryId: number;
    categoryName: string;
    pageCount: number;
    scannedItemCount: number;
  }>;
  rejectionSummary?: Array<{
    reason: string;
    label: string;
    count: number;
    samples: string[];
  }>;
  results: BaseballTicketBayMatchResult[];
};

export type BaseballTicketBayAlertLogItem = {
  id: string;
  clientId: string;
  ownerType: 'client' | 'shared-token';
  ownerId: string;
  ownerLabel?: string | null;
  alertId: string | null;
  alertTitle: string;
  action: 'create' | 'run' | 'pause' | 'resume' | 'delete' | 'push';
  status: 'info' | 'success' | 'warning' | 'error';
  message: string;
  detail: string;
  createdAt: string;
  payload?: BaseballTicketBayRunPayload | null;
};

type BaseballTicketBayAlertMutation = Omit<
  BaseballTicketBayAlertItem,
  'id' | 'clientId' | 'ownerType' | 'ownerId' | 'ownerLabel' | 'createdAt' | 'updatedAt' | 'lastRunAt' | 'lastMatchAt'
>;

type BaseballTicketBayAlertsResponse = {
  ok: boolean;
  includeAllClients?: boolean;
  accessScope?: 'all' | 'client' | 'shared-token';
  scopeOwnerId?: string | null;
  items: BaseballTicketBayAlertItem[];
};

type BaseballTicketBayLogsResponse = {
  ok: boolean;
  includeAllClients?: boolean;
  accessScope?: 'all' | 'client' | 'shared-token';
  scopeOwnerId?: string | null;
  items: BaseballTicketBayAlertLogItem[];
};

export type BaseballTicketBayAlertsResult = {
  items: BaseballTicketBayAlertItem[];
  includeAllClients: boolean;
  accessScope: 'all' | 'client' | 'shared-token';
  scopeOwnerId: string | null;
};

export type BaseballTicketBayLogsResult = {
  items: BaseballTicketBayAlertLogItem[];
  includeAllClients: boolean;
  accessScope: 'all' | 'client' | 'shared-token';
  scopeOwnerId: string | null;
};

type BaseballTicketBayAlertResponse = {
  ok: boolean;
  item: BaseballTicketBayAlertItem;
};

type BaseballTicketBayRunResponse = {
  ok: boolean;
  alert: BaseballTicketBayAlertItem;
  matches: BaseballTicketBayMatchResult[];
  notifiedMatches: BaseballTicketBayMatchResult[];
  log: BaseballTicketBayAlertLogItem;
};

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

  return '/api';
}

const API_BASE_URL = resolveApiBaseUrl();

function normalizeShareToken(value: string | null | undefined) {
  return value?.trim() ?? '';
}

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

  return normalizeShareToken(new URLSearchParams(window.location.search).get('shareToken'));
}

function resolveBaseballTicketBayShareToken() {
  return normalizeShareToken(baseballTicketBayShareTokenOverride) || readShareTokenFromUrl();
}

export function setBaseballTicketBayShareTokenOverride(shareToken: string | null | undefined) {
  baseballTicketBayShareTokenOverride = normalizeShareToken(shareToken);
}

function buildHeaders(headersInit?: HeadersInit, hasJsonBody = false) {
  const headers = appendClientIdHeader(headersInit);
  const registeredToken = getRegisteredAccessToken();
  const shareToken = resolveBaseballTicketBayShareToken();
  const accessToken = shareToken || registeredToken;

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

  if (accessToken && !headers.has('X-Access-Token')) {
    headers.set('X-Access-Token', accessToken);
  }

  return headers;
}

async function request<T>(path: string, init?: (RequestInit & { timeoutMs?: number })) {
  const controller = new AbortController();
  const timeoutMs =
    typeof init?.timeoutMs === 'number' && Number.isFinite(init.timeoutMs)
      ? Math.max(1_000, init.timeoutMs)
      : WORK_SERVER_TIMEOUT_MS;
  const timeoutId = window.setTimeout(() => controller.abort(), timeoutMs);
  const hasBody = init?.body != null;

  try {
    const response = await fetch(`${API_BASE_URL}${path}`, {
      ...init,
      headers: buildHeaders(init?.headers, hasBody),
      signal: controller.signal,
      cache: init?.cache ?? 'no-store',
    });

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

      try {
        const parsed = JSON.parse(text) as { message?: string };
        throw new Error(parsed.message || '야구 티켓베이 요청에 실패했습니다.');
      } catch (error) {
        if (error instanceof Error && error.message !== text) {
          throw error;
        }

        throw new Error(text || '야구 티켓베이 요청에 실패했습니다.');
      }
    }

    return (await response.json()) as T;
  } catch (error) {
    if (error instanceof DOMException && error.name === 'AbortError') {
      throw new Error('야구 티켓베이 응답이 지연됩니다.');
    }

    throw error;
  } finally {
    window.clearTimeout(timeoutId);
  }
}

export async function fetchBaseballTicketBayAlerts() {
  const response = await request<BaseballTicketBayAlertsResponse>('/baseball-ticket-bay/alerts');
  return {
    items: response.items,
    includeAllClients: response.includeAllClients === true,
    accessScope: response.accessScope === 'all' || response.accessScope === 'shared-token' ? response.accessScope : 'client',
    scopeOwnerId: typeof response.scopeOwnerId === 'string' && response.scopeOwnerId.trim() ? response.scopeOwnerId.trim() : null,
  } satisfies BaseballTicketBayAlertsResult;
}

export async function fetchBaseballTicketBayLogs(alertId?: string | null) {
  const params = new URLSearchParams();

  if (alertId) {
    params.set('alertId', alertId);
  }

  const path = params.size > 0 ? `/baseball-ticket-bay/logs?${params.toString()}` : '/baseball-ticket-bay/logs';
  const response = await request<BaseballTicketBayLogsResponse>(path);
  return {
    items: response.items,
    includeAllClients: response.includeAllClients === true,
    accessScope: response.accessScope === 'all' || response.accessScope === 'shared-token' ? response.accessScope : 'client',
    scopeOwnerId: typeof response.scopeOwnerId === 'string' && response.scopeOwnerId.trim() ? response.scopeOwnerId.trim() : null,
  } satisfies BaseballTicketBayLogsResult;
}

export async function deleteBaseballTicketBayLog(logId: string) {
  await request<{ ok: boolean; item: BaseballTicketBayAlertLogItem | null }>(
    `/baseball-ticket-bay/logs/${encodeURIComponent(logId)}`,
    {
      method: 'DELETE',
    },
  );
}

export async function createBaseballTicketBayAlert(payload: BaseballTicketBayAlertMutation) {
  const response = await request<BaseballTicketBayAlertResponse>('/baseball-ticket-bay/alerts', {
    method: 'POST',
    body: JSON.stringify(payload),
  });

  return response.item;
}

export async function updateBaseballTicketBayAlert(alertId: string, payload: Partial<BaseballTicketBayAlertMutation>) {
  const response = await request<BaseballTicketBayAlertResponse>(`/baseball-ticket-bay/alerts/${encodeURIComponent(alertId)}`, {
    method: 'PATCH',
    body: JSON.stringify(payload),
  });

  return response.item;
}

export async function deleteBaseballTicketBayAlert(alertId: string) {
  await request<{ ok: boolean; item: BaseballTicketBayAlertItem | null }>(
    `/baseball-ticket-bay/alerts/${encodeURIComponent(alertId)}`,
    {
      method: 'DELETE',
    },
  );
}

export async function runBaseballTicketBayAlert(alertId: string) {
  return request<BaseballTicketBayRunResponse>(`/baseball-ticket-bay/alerts/${encodeURIComponent(alertId)}/run`, {
    method: 'POST',
    timeoutMs: BASEBALL_TICKET_BAY_RUN_TIMEOUT_MS,
  });
}
