/**
 * Billing Admin Hooks
 *
 * Hooks for managing plans, features, and addons via the billing admin API.
 * These use the versioned billing system that supports grandfathering.
 */

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

// =============================================================================
// Types
// =============================================================================

export interface Feature {
  id: number;
  code: string;
  name: string;
  description: string;
  feature_type: 'boolean' | 'integer';
}

export interface FeatureCreate {
  code: string;
  name: string;
  description?: string;
  feature_type: 'boolean' | 'integer';
}

export interface PlanFeature {
  id: number;
  feature: Feature;
  bool_value: boolean | null;
  int_value: number | null;
  value: boolean | number | null;
}

export interface PlanFeatureWrite {
  feature_code: string;
  bool_value?: boolean | null;
  int_value?: number | null;
}

export interface PlanVersion {
  id: number;
  plan: Plan;
  version: number;
  name: string;
  is_public: boolean;
  is_legacy: boolean;
  starts_at: string | null;
  ends_at: string | null;
  price_monthly_cents: number;
  price_yearly_cents: number;
  // Transaction fees
  transaction_fee_percent: string; // Decimal comes as string from backend
  transaction_fee_fixed_cents: number;
  // Trial
  trial_days: number;
  // Communication pricing (costs when feature is enabled)
  sms_price_per_message_cents: number;
  masked_calling_price_per_minute_cents: number;
  proxy_number_monthly_fee_cents: number;
  // Credit settings
  default_auto_reload_enabled: boolean;
  default_auto_reload_threshold_cents: number;
  default_auto_reload_amount_cents: number;
  // Display settings
  is_most_popular: boolean;
  show_price: boolean;
  marketing_features: string[];
  // Stripe
  stripe_product_id: string;
  stripe_price_id_monthly: string;
  stripe_price_id_yearly: string;
  is_available: boolean;
  // Features (via PlanFeature M2M - permissions/limits stored here)
  features: PlanFeature[];
  subscriber_count: number;
  created_at: string;
}

export interface PlanVersionCreate {
  plan_code: string;
  name: string;
  is_public?: boolean;
  starts_at?: string | null;
  ends_at?: string | null;
  price_monthly_cents: number;
  price_yearly_cents?: number;
  // Transaction fees
  transaction_fee_percent?: number;
  transaction_fee_fixed_cents?: number;
  // Trial
  trial_days?: number;
  // Communication pricing (costs when feature is enabled)
  sms_price_per_message_cents?: number;
  masked_calling_price_per_minute_cents?: number;
  proxy_number_monthly_fee_cents?: number;
  // Credit settings
  default_auto_reload_enabled?: boolean;
  default_auto_reload_threshold_cents?: number;
  default_auto_reload_amount_cents?: number;
  // Display settings
  is_most_popular?: boolean;
  show_price?: boolean;
  marketing_features?: string[];
  // Stripe
  stripe_product_id?: string;
  stripe_price_id_monthly?: string;
  stripe_price_id_yearly?: string;
  // Features (M2M via PlanFeature - permissions/limits)
  features?: PlanFeatureWrite[];
}

export interface PlanVersionUpdate {
  name?: string;
  is_public?: boolean;
  is_legacy?: boolean;
  starts_at?: string | null;
  ends_at?: string | null;
  price_monthly_cents?: number;
  price_yearly_cents?: number;
  // Transaction fees
  transaction_fee_percent?: number;
  transaction_fee_fixed_cents?: number;
  // Trial
  trial_days?: number;
  // Communication pricing (costs when feature is enabled)
  sms_price_per_message_cents?: number;
  masked_calling_price_per_minute_cents?: number;
  proxy_number_monthly_fee_cents?: number;
  // Credit settings
  default_auto_reload_enabled?: boolean;
  default_auto_reload_threshold_cents?: number;
  default_auto_reload_amount_cents?: number;
  // Display settings
  is_most_popular?: boolean;
  show_price?: boolean;
  marketing_features?: string[];
  // Stripe
  stripe_product_id?: string;
  stripe_price_id_monthly?: string;
  stripe_price_id_yearly?: string;
  // Features (M2M via PlanFeature - permissions/limits)
  features?: PlanFeatureWrite[];
}

export interface Plan {
  id: number;
  code: string;
  name: string;
  description: string;
  display_order: number;
  is_active: boolean;
  max_pages: number;
  allow_custom_domains: boolean;
  max_custom_domains: number;
}

export interface PlanWithVersions extends Plan {
  versions: PlanVersion[];
  active_version: PlanVersion | null;
  total_subscribers: number;
}

export interface PlanCreate {
  code: string;
  name: string;
  description?: string;
  display_order?: number;
  is_active?: boolean;
  max_pages?: number;
  allow_custom_domains?: boolean;
  max_custom_domains?: number;
}

export interface AddOnFeature {
  id: number;
  feature: Feature;
  bool_value: boolean | null;
  int_value: number | null;
  value: boolean | number | null;
}

export interface AddOnFeatureWrite {
  feature_code: string;
  bool_value?: boolean | null;
  int_value?: number | null;
}

export interface AddOnProduct {
  id: number;
  code: string;
  name: string;
  description: string;
  price_monthly_cents: number;
  price_one_time_cents: number;
  stripe_product_id: string;
  stripe_price_id: string;
  is_stackable: boolean;
  is_active: boolean;
  features: AddOnFeature[];
}

export interface AddOnProductCreate {
  code: string;
  name: string;
  description?: string;
  price_monthly_cents?: number;
  price_one_time_cents?: number;
  stripe_product_id?: string;
  stripe_price_id?: string;
  is_stackable?: boolean;
  is_active?: boolean;
  features?: AddOnFeatureWrite[];
}

// Grandfathering response when updating a version with subscribers
export interface GrandfatheringResponse {
  message: string;
  old_version: PlanVersion;
  new_version: PlanVersion;
}

// =============================================================================
// Feature Hooks
// =============================================================================

// Note: Billing admin endpoints are at /billing/admin/ not /api/billing/admin/
const BILLING_BASE = '/billing/admin';

export const useFeatures = () => {
  return useQuery<Feature[]>({
    queryKey: ['billingAdmin', 'features'],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/features/`);
      return data;
    },
    staleTime: 5 * 60 * 1000,
  });
};

export const useCreateFeature = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (feature: FeatureCreate) => {
      const { data } = await apiClient.post(`${BILLING_BASE}/features/`, feature);
      return data as Feature;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'features'] });
    },
  });
};

export const useUpdateFeature = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, ...updates }: Partial<FeatureCreate> & { id: number }) => {
      const { data } = await apiClient.patch(`${BILLING_BASE}/features/${id}/`, updates);
      return data as Feature;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'features'] });
    },
  });
};

export const useDeleteFeature = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: number) => {
      await apiClient.delete(`${BILLING_BASE}/features/${id}/`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'features'] });
    },
  });
};

// =============================================================================
// Plan Hooks
// =============================================================================

export const usePlans = () => {
  return useQuery<PlanWithVersions[]>({
    queryKey: ['billingAdmin', 'plans'],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/plans/`);
      return data;
    },
    staleTime: 5 * 60 * 1000,
  });
};

export const usePlan = (id: number) => {
  return useQuery<PlanWithVersions>({
    queryKey: ['billingAdmin', 'plans', id],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/plans/${id}/`);
      return data;
    },
    enabled: !!id,
  });
};

export const useCreatePlan = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (plan: PlanCreate) => {
      const { data } = await apiClient.post(`${BILLING_BASE}/plans/`, plan);
      return data as Plan;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'plans'] });
    },
  });
};

export const useUpdatePlan = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, ...updates }: Partial<PlanCreate> & { id: number }) => {
      const { data } = await apiClient.patch(`${BILLING_BASE}/plans/${id}/`, updates);
      return data as Plan;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'plans'] });
    },
  });
};

export const useDeletePlan = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: number) => {
      await apiClient.delete(`${BILLING_BASE}/plans/${id}/`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'plans'] });
    },
  });
};

// =============================================================================
// Plan Version Hooks
// =============================================================================

export const usePlanVersions = () => {
  return useQuery<PlanVersion[]>({
    queryKey: ['billingAdmin', 'planVersions'],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/plan-versions/`);
      return data;
    },
    staleTime: 5 * 60 * 1000,
  });
};

export const useCreatePlanVersion = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (version: PlanVersionCreate) => {
      const { data } = await apiClient.post(`${BILLING_BASE}/plan-versions/`, version);
      return data as PlanVersion;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin'] });
    },
  });
};

/**
 * Update a plan version.
 *
 * IMPORTANT: If the version has active subscribers, this will:
 * 1. Mark the current version as legacy
 * 2. Create a new version with the updates
 * 3. Return a GrandfatheringResponse with both versions
 *
 * Existing subscribers keep their current version (grandfathering).
 * New subscribers will get the new version.
 */
export const useUpdatePlanVersion = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      id,
      ...updates
    }: PlanVersionUpdate & { id: number }): Promise<PlanVersion | GrandfatheringResponse> => {
      const { data } = await apiClient.patch(`${BILLING_BASE}/plan-versions/${id}/`, updates);
      return data;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin'] });
    },
  });
};

export const useDeletePlanVersion = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: number) => {
      await apiClient.delete(`${BILLING_BASE}/plan-versions/${id}/`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin'] });
    },
  });
};

export const useMarkVersionLegacy = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: number) => {
      const { data } = await apiClient.post(`${BILLING_BASE}/plan-versions/${id}/mark_legacy/`);
      return data as PlanVersion;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin'] });
    },
  });
};

// Force update response type
export interface ForceUpdateResponse {
  message: string;
  version: PlanVersion;
  affected_count: number;
  affected_businesses: string[];
}

// Force update confirmation response (when confirm not provided)
export interface ForceUpdateConfirmRequired {
  detail: string;
  warning: string;
  subscriber_count: number;
  requires_confirm: true;
}

/**
 * DANGEROUS: Force update a plan version in place, affecting all subscribers.
 *
 * This bypasses grandfathering and modifies the plan for ALL existing subscribers.
 * Only superusers can use this action.
 *
 * Usage:
 * 1. Call without confirm to get subscriber count and warning
 * 2. Show warning to user
 * 3. Call with confirm: true to execute
 */
export const useForceUpdatePlanVersion = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      id,
      confirm,
      ...updates
    }: PlanVersionUpdate & { id: number; confirm?: boolean }): Promise<
      ForceUpdateResponse | ForceUpdateConfirmRequired
    > => {
      const { data } = await apiClient.post(
        `${BILLING_BASE}/plan-versions/${id}/force_update/`,
        { ...updates, confirm }
      );
      return data;
    },
    onSuccess: (data) => {
      // Only invalidate if it was a confirmed update (not just checking)
      if ('version' in data) {
        queryClient.invalidateQueries({ queryKey: ['billingAdmin'] });
      }
    },
  });
};

/**
 * Check if response is a confirmation requirement
 */
export const isForceUpdateConfirmRequired = (
  response: ForceUpdateResponse | ForceUpdateConfirmRequired
): response is ForceUpdateConfirmRequired => {
  return 'requires_confirm' in response && response.requires_confirm === true;
};

export const usePlanVersionSubscribers = (id: number) => {
  return useQuery({
    queryKey: ['billingAdmin', 'planVersions', id, 'subscribers'],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/plan-versions/${id}/subscribers/`);
      return data as {
        version: string;
        subscriber_count: number;
        subscribers: Array<{
          business_id: number;
          business_name: string;
          status: string;
          started_at: string;
        }>;
      };
    },
    enabled: !!id,
  });
};

// =============================================================================
// Add-on Product Hooks
// =============================================================================

export const useAddOnProducts = () => {
  return useQuery<AddOnProduct[]>({
    queryKey: ['billingAdmin', 'addons'],
    queryFn: async () => {
      const { data } = await apiClient.get(`${BILLING_BASE}/addons/`);
      return data;
    },
    staleTime: 5 * 60 * 1000,
  });
};

export const useCreateAddOnProduct = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (addon: AddOnProductCreate) => {
      const { data } = await apiClient.post(`${BILLING_BASE}/addons/`, addon);
      return data as AddOnProduct;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'addons'] });
    },
  });
};

export const useUpdateAddOnProduct = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, ...updates }: Partial<AddOnProductCreate> & { id: number }) => {
      const { data } = await apiClient.patch(`${BILLING_BASE}/addons/${id}/`, updates);
      return data as AddOnProduct;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'addons'] });
    },
  });
};

export const useDeleteAddOnProduct = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: number) => {
      await apiClient.delete(`${BILLING_BASE}/addons/${id}/`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['billingAdmin', 'addons'] });
    },
  });
};

// =============================================================================
// Helper Functions
// =============================================================================

/**
 * Check if a mutation response is a grandfathering response
 */
export const isGrandfatheringResponse = (
  response: PlanVersion | GrandfatheringResponse
): response is GrandfatheringResponse => {
  return 'message' in response && 'old_version' in response && 'new_version' in response;
};

/**
 * Format cents to dollars string
 */
export const formatCentsToDollars = (cents: number): string => {
  return (cents / 100).toFixed(2);
};

/**
 * Convert dollars to cents
 */
export const dollarsToCents = (dollars: number): number => {
  return Math.round(dollars * 100);
};
