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

export type StockAlertFilterValue = 'all' | 'price' | 'top3';
export type StockAlertType = Exclude<StockAlertFilterValue, 'all'>;

export type StockAlertItem = {
  id: string;
  stockCode: string;
  stockName: string;
  alertTypes: StockAlertType[];
  alertTypeLabels: string[];
  currentPrice: number | null;
  changeRate: number | null;
  volumeRate5d: number | null;
  quotedAt: string | null;
  createdAt: string;
  updatedAt: string;
};

export type StockAlertDraftRow = {
  id: string;
  persistedId: string | null;
  stockCode: string;
  stockName: string;
  alertTypes: StockAlertType[];
  alertTypeLabels: string[];
  currentPrice: number | null;
  changeRate: number | null;
  volumeRate5d: number | null;
  quotedAt: string | null;
  createdAt: string | null;
  updatedAt: string | null;
  isDirty: boolean;
  isNew: boolean;
};

export type StockAlertSearchItem = {
  stockCode: string;
  stockName: string;
  market: string;
};

const WORK_SERVER_TIMEOUT_MS = 10000;

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

  return '/api';
}

const WORK_SERVER_BASE_URL = resolveWorkServerBaseUrl();

function toDraftRow(item: StockAlertItem): StockAlertDraftRow {
  return {
    id: item.id,
    persistedId: item.id,
    stockCode: item.stockCode,
    stockName: item.stockName,
    alertTypes: item.alertTypes,
    alertTypeLabels: item.alertTypeLabels,
    currentPrice: item.currentPrice,
    changeRate: item.changeRate,
    volumeRate5d: item.volumeRate5d,
    quotedAt: item.quotedAt,
    createdAt: item.createdAt,
    updatedAt: item.updatedAt,
    isDirty: false,
    isNew: false,
  };
}

export function createEmptyStockAlertRow(): StockAlertDraftRow {
  const localId = `stock-alert-draft-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;

  return {
    id: localId,
    persistedId: null,
    stockCode: '',
    stockName: '',
    alertTypes: ['price'],
    alertTypeLabels: ['현재가'],
    currentPrice: null,
    changeRate: null,
    volumeRate5d: null,
    quotedAt: null,
    createdAt: null,
    updatedAt: null,
    isDirty: true,
    isNew: true,
  };
}

async function request<T>(path: string, init?: RequestInit) {
  const headers = appendClientIdHeader(init?.headers);
  const controller = new AbortController();
  const timeoutId = window.setTimeout(() => controller.abort(), WORK_SERVER_TIMEOUT_MS);

  if (init?.body && !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);
  }

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

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

      try {
        const payload = JSON.parse(text) as { message?: string };
        throw new Error(payload.message || '종목 알림 요청에 실패했습니다.');
      } catch {
        throw new Error(text || '종목 알림 요청에 실패했습니다.');
      }
    }

    return response.json() as Promise<T>;
  } finally {
    window.clearTimeout(timeoutId);
  }
}

export async function fetchStockAlerts(filterValue: StockAlertFilterValue) {
  const searchParams = new URLSearchParams();

  if (filterValue !== 'all') {
    searchParams.set('alertType', filterValue);
  }

  const path = `/stock-alerts${searchParams.size ? `?${searchParams.toString()}` : ''}`;
  const response = await request<{ items: StockAlertItem[] }>(path);
  return response.items.map(toDraftRow);
}

export async function searchStockAlertCandidates(query: string, limit = 20) {
  const searchParams = new URLSearchParams({
    query: query.trim(),
    limit: String(limit),
  });
  const response = await request<{ items: StockAlertSearchItem[] }>(`/stock-alerts/search?${searchParams.toString()}`);
  return response.items;
}

export async function saveStockAlertRows(rows: StockAlertDraftRow[]) {
  const payload = rows.map((row) => ({
    id: row.persistedId ?? undefined,
    stockCode: row.stockCode,
    stockName: row.stockName,
    alertTypes: row.alertTypes,
  }));
  const response = await request<{ items: StockAlertItem[] }>('/stock-alerts/batch', {
    method: 'PUT',
    body: JSON.stringify({ items: payload }),
  });

  return response.items.map(toDraftRow);
}

export async function deleteStockAlertRow(id: string) {
  await request<{ ok: boolean; id: string }>(`/stock-alerts/${encodeURIComponent(id)}`, {
    method: 'DELETE',
  });
}
