import { CareInfo, IdentificationResult, Language, PlantHealthCheck } from '../../types';

export type PlanId = 'free' | 'pro';
export type BillingProvider = 'mock' | 'revenuecat' | 'stripe';
export type PurchaseProductId = 'monthly_pro' | 'yearly_pro' | 'topup_small' | 'topup_medium' | 'topup_large';
export type SimulatedWebhookEvent =
  | 'entitlement_granted'
  | 'entitlement_revoked'
  | 'topup_granted'
  | 'credits_depleted';

export interface BackendDatabaseEntry extends IdentificationResult {
  imageUri: string;
  imageStatus?: 'ok' | 'missing' | 'invalid';
  categories: string[];
}

export interface CreditState {
  monthlyAllowance: number;
  usedThisCycle: number;
  topupBalance: number;
  available: number;
  cycleStartedAt: string;
  cycleEndsAt: string;
}

export interface EntitlementState {
  plan: PlanId;
  provider: BillingProvider;
  status: 'active' | 'inactive';
  renewsAt: string | null;
}

export interface BillingSummary {
  entitlement: EntitlementState;
  credits: CreditState;
  availableProducts: PurchaseProductId[];
}

export interface RevenueCatEntitlementInfo {
  productIdentifier?: string;
  expirationDate?: string | null;
  expiresDate?: string | null;
}

export interface RevenueCatNonSubscriptionTransaction {
  productIdentifier?: string;
  transactionIdentifier?: string;
  transactionId?: string;
  purchaseDate?: string | null;
}

export interface RevenueCatCustomerInfo {
  appUserId?: string | null;
  originalAppUserId?: string | null;
  entitlements: {
    active: Record<string, RevenueCatEntitlementInfo>;
  };
  nonSubscriptions?: Record<string, RevenueCatNonSubscriptionTransaction[]>;
  allPurchasedProductIdentifiers?: string[];
  latestExpirationDate?: string | null;
}

export interface ScanPlantRequest {
  userId: string;
  idempotencyKey: string;
  imageUri: string;
  language: Language;
}

export interface ScanPlantResponse {
  result: IdentificationResult;
  creditsCharged: number;
  modelPath: string[];
  modelUsed?: string | null;
  modelFallbackCount?: number;
  billing: BillingSummary;
}

export interface SemanticSearchRequest {
  userId: string;
  idempotencyKey: string;
  query: string;
  language: Language;
}

export interface SemanticSearchResponse {
  status: 'success' | 'no_results';
  results: BackendDatabaseEntry[];
  creditsCharged: number;
  billing: BillingSummary;
}

export interface HealthCheckRequest {
  userId: string;
  idempotencyKey: string;
  imageUri: string;
  language: Language;
  plantContext?: {
    name: string;
    botanicalName: string;
    careInfo: CareInfo;
    description?: string;
  };
}

export interface HealthCheckResponse {
  healthCheck: PlantHealthCheck;
  creditsCharged: number;
  modelUsed?: string | null;
  modelFallbackCount?: number;
  billing: BillingSummary;
}

export interface ServiceHealthResponse {
  ok: boolean;
  uptimeSec: number;
  timestamp: string;
  openAiConfigured: boolean;
  dbReady?: boolean;
  dbPath?: string;
  scanModel?: string;
  healthModel?: string;
}

export interface SimulatePurchaseRequest {
  userId: string;
  idempotencyKey: string;
  productId: PurchaseProductId;
}

export interface SimulatePurchaseResponse {
  appliedProduct: PurchaseProductId;
  billing: BillingSummary;
}

export interface SimulateWebhookRequest {
  userId: string;
  idempotencyKey: string;
  event: SimulatedWebhookEvent;
  payload?: {
    credits?: number;
  };
}

export interface SimulateWebhookResponse {
  event: SimulatedWebhookEvent;
  billing: BillingSummary;
}

export type RevenueCatSyncSource =
  | 'app_init'
  | 'subscription_purchase'
  | 'topup_purchase'
  | 'restore';

export interface SyncRevenueCatStateResponse {
  billing: BillingSummary;
  syncedAt: string;
}

export type BackendErrorCode =
  | 'INSUFFICIENT_CREDITS'
  | 'UNAUTHORIZED'
  | 'TIMEOUT'
  | 'NETWORK_ERROR'
  | 'PROVIDER_ERROR'
  | 'BAD_REQUEST';

export class BackendApiError extends Error {
  public readonly code: BackendErrorCode;
  public readonly status: number;
  public readonly metadata?: Record<string, unknown>;

  constructor(
    code: BackendErrorCode,
    message: string,
    status = 500,
    metadata?: Record<string, unknown>,
  ) {
    super(message);
    this.name = 'BackendApiError';
    this.code = code;
    this.status = status;
    this.metadata = metadata;
  }
}

export const isBackendApiError = (error: unknown): error is BackendApiError => {
  return error instanceof BackendApiError;
};
