import apiClient from './client';
import { getYandexCid } from '../utils/yandexCid';
import type {
  Subscription,
  SubscriptionStatusResponse,
  SubscriptionListItem,
  SubscriptionsListResponse,
  RenewalOption,
  TrafficPackage,
  TrialInfo,
  PurchaseOptions,
  PurchaseSelection,
  PurchasePreview,
  AppConfig,
  SbpRecurringInfo,
} from '../types';

/** Helper: build query params with optional subscription_id */
const withSubId = (subscriptionId?: number, extra?: Record<string, unknown>) => ({
  params: {
    ...(subscriptionId != null && { subscription_id: subscriptionId }),
    ...extra,
  },
});

/**
 * Helper for POST/PATCH/PUT: returns [body, axiosConfig] tuple.
 * subscription_id goes as query param (backend expects Query(...)), NOT in body.
 */
const bodyWithSubId = (
  body: Record<string, unknown>,
  subscriptionId?: number,
): [Record<string, unknown>, { params?: Record<string, unknown> }] => [
  body,
  subscriptionId != null ? { params: { subscription_id: subscriptionId } } : {},
];

export const subscriptionApi = {
  // ── Multi-tariff endpoints ──────────────────────────────────────────

  getSubscriptions: async (): Promise<SubscriptionsListResponse> => {
    const response = await apiClient.get<SubscriptionsListResponse>('/cabinet/subscriptions');
    return response.data;
  },

  getSubscriptionById: async (subscriptionId: number): Promise<SubscriptionListItem> => {
    const response = await apiClient.get<SubscriptionListItem>(
      `/cabinet/subscriptions/${subscriptionId}`,
    );
    return response.data;
  },

  deleteSubscription: async (subscriptionId: number): Promise<{ message: string }> => {
    const response = await apiClient.delete(`/cabinet/subscriptions/${subscriptionId}`);
    return response.data;
  },

  // ── Legacy single-subscription status ───────────────────────────────

  getSubscription: async (subscriptionId?: number): Promise<SubscriptionStatusResponse> => {
    const response = await apiClient.get<SubscriptionStatusResponse>(
      '/cabinet/subscription',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── Renewal ─────────────────────────────────────────────────────────

  getRenewalOptions: async (subscriptionId?: number): Promise<RenewalOption[]> => {
    const response = await apiClient.get<RenewalOption[]>(
      '/cabinet/subscription/renewal-options',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  renewSubscription: async (
    periodDays: number,
    subscriptionId?: number,
  ): Promise<{
    message: string;
    new_end_date: string;
    amount_paid_kopeks: number;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/renew',
      ...bodyWithSubId(
        { period_days: periodDays, yandex_cid: getYandexCid() || undefined },
        subscriptionId,
      ),
    );
    return response.data;
  },

  // ── Traffic ─────────────────────────────────────────────────────────

  getTrafficPackages: async (subscriptionId?: number): Promise<TrafficPackage[]> => {
    const response = await apiClient.get<TrafficPackage[]>(
      '/cabinet/subscription/traffic-packages',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  purchaseTraffic: async (
    gb: number,
    subscriptionId?: number,
  ): Promise<{
    message: string;
    gb_added: number;
    amount_paid_kopeks: number;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/traffic',
      ...bodyWithSubId({ gb, yandex_cid: getYandexCid() || undefined }, subscriptionId),
    );
    return response.data;
  },

  switchTraffic: async (
    gb: number,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    old_traffic_gb: number;
    new_traffic_gb: number;
    charged_kopeks: number;
    balance_kopeks: number;
    balance_label: string;
  }> => {
    const response = await apiClient.put(
      '/cabinet/subscription/traffic',
      ...bodyWithSubId({ gb, yandex_cid: getYandexCid() || undefined }, subscriptionId),
    );
    return response.data;
  },

  saveTrafficCart: async (trafficGb: number, subscriptionId?: number): Promise<void> => {
    await apiClient.post(
      '/cabinet/subscription/traffic/save-cart',
      ...bodyWithSubId({ gb: trafficGb }, subscriptionId),
    );
  },

  refreshTraffic: async (
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    cached: boolean;
    rate_limited?: boolean;
    retry_after_seconds?: number;
    source?: string;
    traffic_used_bytes: number;
    traffic_used_gb: number;
    traffic_limit_bytes: number;
    traffic_limit_gb: number;
    traffic_used_percent: number;
    is_unlimited: boolean;
    lifetime_used_bytes?: number;
    lifetime_used_gb?: number;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/refresh-traffic',
      {},
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── Devices ─────────────────────────────────────────────────────────

  purchaseDevices: async (
    devices: number,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    devices_added: number;
    new_device_limit: number;
    price_kopeks: number;
    price_label: string;
    balance_kopeks: number;
    balance_label: string;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/devices/purchase',
      ...bodyWithSubId({ devices, yandex_cid: getYandexCid() || undefined }, subscriptionId),
    );
    return response.data;
  },

  getDevicePrice: async (
    devices: number = 1,
    subscriptionId?: number,
  ): Promise<{
    available: boolean;
    reason?: string;
    devices?: number;
    price_per_device_kopeks?: number;
    price_per_device_label?: string;
    total_price_kopeks?: number;
    total_price_label?: string;
    current_device_limit?: number;
    max_device_limit?: number;
    can_add?: number;
    days_left?: number;
    base_device_price_kopeks?: number;
    original_price_per_device_kopeks?: number;
    base_total_price_kopeks?: number;
    discount_percent?: number;
    discount_kopeks?: number;
  }> => {
    const response = await apiClient.get('/cabinet/subscription/devices/price', {
      params: {
        devices,
        ...(subscriptionId != null && { subscription_id: subscriptionId }),
      },
    });
    return response.data;
  },

  saveDevicesCart: async (devices: number, subscriptionId?: number): Promise<void> => {
    await apiClient.post(
      '/cabinet/subscription/devices/save-cart',
      ...bodyWithSubId({ devices }, subscriptionId),
    );
  },

  getDeviceReductionInfo: async (
    subscriptionId?: number,
  ): Promise<{
    available: boolean;
    reason?: string;
    current_device_limit: number;
    min_device_limit: number;
    can_reduce: number;
    connected_devices_count: number;
  }> => {
    const response = await apiClient.get(
      '/cabinet/subscription/devices/reduction-info',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  reduceDevices: async (
    newDeviceLimit: number,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    old_device_limit: number;
    new_device_limit: number;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/devices/reduce',
      ...bodyWithSubId({ new_device_limit: newDeviceLimit }, subscriptionId),
    );
    return response.data;
  },

  getDevices: async (
    subscriptionId?: number,
  ): Promise<{
    devices: Array<{
      hwid: string;
      platform: string;
      device_model: string;
      created_at: string | null;
      local_name?: string | null;
    }>;
    total: number;
    device_limit: number;
  }> => {
    const response = await apiClient.get(
      '/cabinet/subscription/devices',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  /**
   * Persist a user-local alias for a device. Pass an empty/null `name` to
   * clear the alias. Returns the final `local_name` after server-side
   * normalization (trimmed + length-capped).
   *
   * Scope is per-(user, hwid), so the same alias appears across all of
   * the user's subscriptions in multi-tariff mode.
   */
  renameDevice: async (
    hwid: string,
    name: string | null,
    subscriptionId?: number,
  ): Promise<{ hwid: string; local_name: string | null }> => {
    const response = await apiClient.patch(
      `/cabinet/subscription/devices/${encodeURIComponent(hwid)}/name`,
      { name },
      withSubId(subscriptionId),
    );
    return response.data;
  },

  deleteDevice: async (
    hwid: string,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    deleted_hwid: string;
  }> => {
    const response = await apiClient.delete(
      `/cabinet/subscription/devices/${encodeURIComponent(hwid)}`,
      withSubId(subscriptionId),
    );
    return response.data;
  },

  deleteAllDevices: async (
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    deleted_count: number;
  }> => {
    const response = await apiClient.delete(
      '/cabinet/subscription/devices',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── Autopay ─────────────────────────────────────────────────────────

  updateAutopay: async (
    enabled: boolean,
    daysBefore?: number,
    subscriptionId?: number,
  ): Promise<{
    message: string;
    autopay_enabled: boolean;
    autopay_days_before: number;
  }> => {
    const response = await apiClient.patch(
      '/cabinet/subscription/autopay',
      { enabled, days_before: daysBefore },
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── SBP recurring (Platega) ───────────────────────────────────────────

  getSbpRecurring: async (subscriptionId?: number): Promise<SbpRecurringInfo> => {
    const response = await apiClient.get<SbpRecurringInfo>(
      '/cabinet/subscription/platega-recurrent',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  enableSbpRecurring: async (
    subscriptionId?: number,
  ): Promise<{ status: string; redirect_url: string | null }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/platega-recurrent/enable',
      ...bodyWithSubId({}, subscriptionId),
    );
    return response.data;
  },

  cancelSbpRecurring: async (subscriptionId?: number): Promise<{ status: string }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/platega-recurrent/cancel',
      ...bodyWithSubId({}, subscriptionId),
    );
    return response.data;
  },

  /**
   * Оформление подписки на тариф через СБП-автопродление: первое списание =
   * подтверждение привязки в банке. Для нового тарифа бэкенд создаёт
   * неактивную заготовку, которую активирует первый чардж.
   */
  purchaseWithSbpRecurring: async (
    tariffId: number,
  ): Promise<{ status: string; redirect_url: string | null; subscription_id: number }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/platega-recurrent/purchase',
      {},
      { params: { tariff_id: tariffId } },
    );
    return response.data;
  },

  // ── Trial ───────────────────────────────────────────────────────────

  getTrialInfo: async (): Promise<TrialInfo> => {
    const response = await apiClient.get<TrialInfo>('/cabinet/subscription/trial');
    return response.data;
  },

  activateTrial: async (): Promise<Subscription> => {
    const response = await apiClient.post<Subscription>('/cabinet/subscription/trial', {
      yandex_cid: getYandexCid() || undefined,
    });
    return response.data;
  },

  // ── Purchase ────────────────────────────────────────────────────────

  getPurchaseOptions: async (subscriptionId?: number): Promise<PurchaseOptions> => {
    const response = await apiClient.get<PurchaseOptions>(
      '/cabinet/subscription/purchase-options',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  previewPurchase: async (
    selection: PurchaseSelection,
    subscriptionId?: number,
  ): Promise<PurchasePreview> => {
    const response = await apiClient.post<PurchasePreview>(
      '/cabinet/subscription/purchase-preview',
      ...bodyWithSubId({ selection }, subscriptionId),
    );
    return response.data;
  },

  submitPurchase: async (
    selection: PurchaseSelection,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    subscription: Subscription;
    was_trial_conversion: boolean;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/purchase',
      ...bodyWithSubId({ selection, yandex_cid: getYandexCid() || undefined }, subscriptionId),
    );
    return response.data;
  },

  purchaseTariff: async (
    tariffId: number,
    periodDays: number,
    trafficGb?: number,
    /**
     * Subscription ID being renewed. Pass this when the user clicked
     * "Renew" on an existing subscription so the backend can resolve
     * the target row by ID instead of doing a (user_id, tariff_id)
     * re-lookup that races with concurrent panel webhooks. Omit when
     * this is a fresh purchase from the catalog.
     */
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    subscription: Subscription;
    tariff_id: number;
    tariff_name: string;
    balance_kopeks: number;
    balance_label: string;
  }> => {
    const response = await apiClient.post('/cabinet/subscription/purchase-tariff', {
      tariff_id: tariffId,
      period_days: periodDays,
      traffic_gb: trafficGb,
      subscription_id: subscriptionId,
      yandex_cid: getYandexCid() || undefined,
    });
    return response.data;
  },

  // ── Countries / Servers ─────────────────────────────────────────────

  getCountries: async (
    subscriptionId?: number,
  ): Promise<{
    countries: Array<{
      uuid: string;
      name: string;
      country_code: string | null;
      base_price_kopeks: number;
      price_kopeks: number;
      price_per_month_kopeks: number;
      price_rubles: number;
      is_available: boolean;
      is_connected: boolean;
      has_discount: boolean;
      discount_percent: number;
    }>;
    connected_count: number;
    has_subscription: boolean;
    days_left: number;
    discount_percent: number;
  }> => {
    const response = await apiClient.get(
      '/cabinet/subscription/countries',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  updateCountries: async (
    countries: string[],
    subscriptionId?: number,
  ): Promise<{
    message: string;
    added: string[];
    removed: string[];
    amount_paid_kopeks: number;
    connected_squads: string[];
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/countries',
      ...bodyWithSubId({ countries, yandex_cid: getYandexCid() || undefined }, subscriptionId),
    );
    return response.data;
  },

  // ── Connection ──────────────────────────────────────────────────────

  getConnectionLink: async (
    subscriptionId?: number,
  ): Promise<{
    subscription_url: string | null;
    display_link: string | null;
    happ_redirect_link: string | null;
    happ_scheme_link: string | null;
    happ_cryptolink?: string | null;
    happ_crypto_link?: string | null;
    happ_link?: string | null;
    connect_mode: string;
    hide_link: boolean;
    instructions: {
      steps: string[];
    };
  }> => {
    const response = await apiClient.get(
      '/cabinet/subscription/connection-link',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  getHappDownloads: async (): Promise<{
    platforms: Record<
      string,
      {
        name: string;
        icon: string;
        link: string;
      }
    >;
    happ_enabled: boolean;
  }> => {
    const response = await apiClient.get('/cabinet/subscription/happ-downloads');
    return response.data;
  },

  getAppConfig: async (subscriptionId?: number): Promise<AppConfig> => {
    const response = await apiClient.get<AppConfig>(
      '/cabinet/subscription/app-config',
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── Tariff switch ───────────────────────────────────────────────────

  previewTariffSwitch: async (
    tariffId: number,
    subscriptionId?: number,
  ): Promise<{
    can_switch: boolean;
    current_tariff_id: number | null;
    current_tariff_name: string | null;
    new_tariff_id: number;
    new_tariff_name: string;
    remaining_days: number;
    upgrade_cost_kopeks: number;
    upgrade_cost_label: string;
    balance_kopeks: number;
    balance_label: string;
    has_enough_balance: boolean;
    missing_amount_kopeks: number;
    missing_amount_label: string;
    is_upgrade: boolean;
    base_upgrade_cost_kopeks?: number;
    discount_percent?: number;
    discount_kopeks?: number;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/tariff/switch/preview',
      ...bodyWithSubId({ tariff_id: tariffId, period_days: 30 }, subscriptionId),
    );
    return response.data;
  },

  switchTariff: async (
    tariffId: number,
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    subscription: Subscription;
    old_tariff_name: string;
    new_tariff_id: number;
    new_tariff_name: string;
    charged_kopeks: number;
    balance_kopeks: number;
    balance_label: string;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/tariff/switch',
      ...bodyWithSubId(
        { tariff_id: tariffId, period_days: 30, yandex_cid: getYandexCid() || undefined },
        subscriptionId,
      ),
    );
    return response.data;
  },

  // ── Revoke (reissue) ────────────────────────────────────────────────

  revokeSubscription: async (subscriptionId?: number) => {
    const response = await apiClient.post(
      '/cabinet/subscription/revoke',
      undefined,
      withSubId(subscriptionId),
    );
    return response.data;
  },

  // ── Daily subscription ──────────────────────────────────────────────

  togglePause: async (
    subscriptionId?: number,
  ): Promise<{
    success: boolean;
    message: string;
    is_paused: boolean;
    balance_kopeks: number;
    balance_label: string;
  }> => {
    const response = await apiClient.post(
      '/cabinet/subscription/pause',
      undefined,
      withSubId(subscriptionId),
    );
    return response.data;
  },
};
