import config from '@blocklet/sdk/lib/config';
import Joi from 'joi';

import logger from '../logger';

export type RetentionPreferences = {
  retentionEnabled?: boolean;
  scheduleEnabled?: boolean;
  scheduleHour?: number;
  batchSize?: number;
  minFreeDiskMB?: number;
};

export type RetentionPolicyConfig = {
  enabled: boolean;
  defaults: {
    retentionDays: number;
    batchSize: number;
  };
  schedule: {
    enabled: boolean;
    hour: number;
    cron: string;
  };
  storage: {
    minFreeDiskMB: number;
    maxArchiveFiles: number;
  };
  tables: Record<string, TableRetentionPolicy>;
};

export type TableRetentionPolicy = {
  enabled: boolean;
  retentionDays: number;
  allowRestore?: boolean;
  archivableStatuses?: string[];
  excludeConditions?: {
    hasActiveSubscription?: boolean;
    statuses?: string[];
    customCondition?: string;
  };
  /**
   * Cascade relations: child tables to archive together with this table.
   * Format: { childTable: foreignKeyField }
   * Example: { invoice_items: 'invoice_id' } means when archiving an invoice,
   * also archive all invoice_items where invoice_id matches.
   */
  cascadeRelations?: Record<string, string>;
};

const preferencesSchema = Joi.object<RetentionPreferences>({
  retentionEnabled: Joi.boolean().default(false),
  scheduleEnabled: Joi.boolean().default(true),
  scheduleHour: Joi.number().integer().min(0).max(23).default(2),
  batchSize: Joi.number().integer().min(100).max(500).default(500),
  minFreeDiskMB: Joi.number().integer().min(100).default(1000),
});

const DEFAULT_TABLE_POLICIES: Record<string, TableRetentionPolicy> = {
  meter_events: {
    enabled: true,
    retentionDays: 90,
    archivableStatuses: ['completed', 'canceled'],
    excludeConditions: {
      statuses: ['pending', 'processing', 'requires_action', 'requires_capture'],
      hasActiveSubscription: true,
    },
  },
  credit_transactions: {
    enabled: true,
    retentionDays: 90,
    excludeConditions: {
      hasActiveSubscription: true,
    },
  },
  events: {
    enabled: true,
    retentionDays: 90,
    excludeConditions: {
      customCondition: 'pending_webhooks > 0',
    },
  },
  webhook_attempts: {
    enabled: true,
    retentionDays: 90,
  },
  jobs: {
    enabled: false,
    retentionDays: -1,
  },
  payment_intents: {
    enabled: true,
    retentionDays: 730,
    archivableStatuses: ['succeeded', 'canceled'],
    excludeConditions: {
      statuses: [
        'requires_payment_method',
        'requires_confirmation',
        'requires_action',
        'processing',
        'requires_capture',
      ],
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  invoices: {
    enabled: true,
    retentionDays: 730,
    archivableStatuses: ['paid', 'void', 'uncollectible'],
    excludeConditions: {
      statuses: ['draft', 'open'],
      hasActiveSubscription: true,
    },
    allowRestore: false,
    cascadeRelations: {
      invoice_items: 'invoice_id',
    },
  },
  refunds: {
    enabled: true,
    retentionDays: 730,
    archivableStatuses: ['succeeded', 'failed', 'canceled'],
    excludeConditions: {
      statuses: ['pending', 'requires_action'],
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  payouts: {
    enabled: true,
    retentionDays: 730,
    archivableStatuses: ['paid', 'failed', 'canceled', 'reverted'],
    excludeConditions: {
      statuses: ['pending', 'in_transit', 'deferred'],
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  subscriptions: {
    enabled: true,
    retentionDays: 365,
    archivableStatuses: ['canceled', 'incomplete_expired'],
    excludeConditions: {
      statuses: ['active', 'past_due', 'trialing', 'paused', 'incomplete'],
    },
    allowRestore: false,
    cascadeRelations: {
      subscription_items: 'subscription_id',
      subscription_schedules: 'subscription_id',
    },
  },
  credit_grants: {
    enabled: true,
    retentionDays: 365,
    archivableStatuses: ['depleted', 'expired', 'voided'],
    excludeConditions: {
      statuses: ['pending', 'granted'],
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  products: {
    enabled: false,
    retentionDays: -1,
  },
  prices: {
    enabled: false,
    retentionDays: -1,
  },
  coupons: {
    enabled: false,
    retentionDays: -1,
  },
  checkout_sessions: {
    enabled: true,
    retentionDays: 365,
    archivableStatuses: ['complete', 'expired'],
    excludeConditions: {
      statuses: ['open'],
      hasActiveSubscription: true,
    },
  },
  customers: {
    enabled: false,
    retentionDays: -1,
  },
  discounts: {
    enabled: true,
    retentionDays: 365,
    excludeConditions: {
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  usage_records: {
    enabled: true,
    retentionDays: 90,
    excludeConditions: {
      hasActiveSubscription: true,
    },
    allowRestore: false,
  },
  price_quotes: {
    enabled: true,
    retentionDays: 90,
    archivableStatuses: ['expired', 'used'],
    excludeConditions: {
      statuses: ['active', 'pending'],
    },
    allowRestore: false,
  },
  setup_intents: {
    enabled: true,
    retentionDays: 365,
    archivableStatuses: ['succeeded', 'canceled'],
    excludeConditions: {
      statuses: ['requires_payment_method', 'requires_confirmation', 'requires_action', 'processing'],
    },
    allowRestore: false,
  },
};

export const getArchiveCronExpression = (hour: number) => `0 0 ${hour} * * 3`;

export function getRetentionConfig(): RetentionPolicyConfig {
  const prefs = (config.env?.preferences || {}) as RetentionPreferences;
  const { value: rawValue, error } = preferencesSchema.validate(prefs, { stripUnknown: true });
  // On validation error, log and fall back to schema defaults to enforce constraints (e.g. batchSize max)
  const value = error ? preferencesSchema.validate({}, { stripUnknown: true }).value : rawValue;
  if (error) {
    logger.error('validate retention preferences error', { error });
  }

  const scheduleHour = value?.scheduleHour ?? 2;

  return {
    enabled: value?.retentionEnabled ?? false,
    defaults: {
      retentionDays: 365,
      batchSize: value?.batchSize ?? 500,
    },
    schedule: {
      enabled: value?.scheduleEnabled ?? true,
      hour: scheduleHour,
      cron: getArchiveCronExpression(scheduleHour),
    },
    storage: {
      minFreeDiskMB: value?.minFreeDiskMB ?? 1000, // 1GB min free space (yearly archives can be large)
      maxArchiveFiles: 10, // Keep 10 years of archive files (one per year)
    },
    tables: DEFAULT_TABLE_POLICIES,
  };
}
