/**
 * Repository Interface - Generic repository contract
 *
 * @module platform-marketing-content/shared/repositories
 */

/**
 * Service context with tenant and user info
 */
export interface ServiceContext {
  tenantId: string;
  userId: string;
}

/**
 * Query options for repository methods
 */
export interface QueryOptions {
  includeDeleted?: boolean;
  relations?: string[];
}

/**
 * Pagination request options
 */
export interface PaginationOptions {
  page?: number;
  limit?: number;
  sortBy?: string;
  sortOrder?: 'asc' | 'desc';
}

/**
 * Pagination metadata
 */
export interface PaginationMeta {
  total: number;
  page: number;
  limit: number;
  totalPages: number;
  hasNext: boolean;
  hasPrev: boolean;
}

/**
 * Paginated response wrapper
 */
export interface PaginatedResult<T> {
  data: T[];
  meta: PaginationMeta;
}

/**
 * Generic repository interface for data access
 *
 * This interface defines the contract for repository implementations,
 * supporting TypeORM-based data access patterns.
 *
 * @template T - Entity type
 *
 * @example
 * ```typescript
 * export class ProjectRepository implements IBaseRepository<Project> {
 *   async findById(ctx: ServiceContext, id: string): Promise<Project | null> {
 *     // Implementation
 *   }
 * }
 * ```
 */
export interface IBaseRepository<T> {
  /**
   * Find entity by ID
   */
  findById(
    ctx: ServiceContext,
    id: string,
    options?: QueryOptions,
  ): Promise<T | null>;

  /**
   * Find one entity by criteria
   */
  findOne(
    ctx: ServiceContext,
    criteria: Partial<T>,
    options?: QueryOptions,
  ): Promise<T | null>;

  /**
   * Find all entities with pagination
   */
  findAll(
    ctx: ServiceContext,
    filters?: PaginationOptions & Partial<T>,
    options?: QueryOptions,
  ): Promise<PaginatedResult<T>>;

  /**
   * Find multiple entities by criteria
   */
  findMany(
    ctx: ServiceContext,
    criteria: Partial<T>,
    options?: QueryOptions,
  ): Promise<T[]>;

  /**
   * Create new entity
   */
  create(ctx: ServiceContext, data: Partial<T>): Promise<T>;

  /**
   * Create multiple entities
   */
  createMany(ctx: ServiceContext, data: Partial<T>[]): Promise<T[]>;

  /**
   * Update existing entity
   */
  update(ctx: ServiceContext, id: string, data: Partial<T>): Promise<T | null>;

  /**
   * Update multiple entities by criteria
   */
  updateMany(
    ctx: ServiceContext,
    criteria: Partial<T>,
    data: Partial<T>,
  ): Promise<number>;

  /**
   * Soft delete entity
   */
  softDelete(ctx: ServiceContext, id: string): Promise<boolean>;

  /**
   * Hard delete entity
   */
  hardDelete(ctx: ServiceContext, id: string): Promise<boolean>;

  /**
   * Delete multiple entities by criteria
   */
  deleteMany(ctx: ServiceContext, criteria: Partial<T>): Promise<number>;

  /**
   * Count entities matching criteria
   */
  count(
    ctx: ServiceContext,
    criteria?: Partial<T>,
    options?: QueryOptions,
  ): Promise<number>;

  /**
   * Check if entity exists
   */
  exists(
    ctx: ServiceContext,
    id: string,
    options?: QueryOptions,
  ): Promise<boolean>;

  /**
   * Execute raw SQL query
   */
  query<R = unknown>(
    ctx: ServiceContext,
    sql: string,
    params: unknown[],
  ): Promise<R[]>;

  /**
   * Execute raw SQL query and return first result
   */
  queryOne<R = unknown>(
    ctx: ServiceContext,
    sql: string,
    params: unknown[],
  ): Promise<R | null>;
}

/**
 * Read-only repository interface
 *
 * For repositories that only need read operations (e.g., views, reports)
 *
 * @template T - Entity type
 */
export interface IReadOnlyRepository<T> {
  findById(
    ctx: ServiceContext,
    id: string,
    options?: QueryOptions,
  ): Promise<T | null>;

  findOne(
    ctx: ServiceContext,
    criteria: Partial<T>,
    options?: QueryOptions,
  ): Promise<T | null>;

  findAll(
    ctx: ServiceContext,
    filters?: PaginationOptions & Partial<T>,
    options?: QueryOptions,
  ): Promise<PaginatedResult<T>>;

  findMany(
    ctx: ServiceContext,
    criteria: Partial<T>,
    options?: QueryOptions,
  ): Promise<T[]>;

  count(
    ctx: ServiceContext,
    criteria?: Partial<T>,
    options?: QueryOptions,
  ): Promise<number>;

  exists(
    ctx: ServiceContext,
    id: string,
    options?: QueryOptions,
  ): Promise<boolean>;
}

/**
 * Write-only repository interface
 *
 * For repositories that only need write operations (e.g., event stores, audit logs)
 *
 * @template T - Entity type
 */
export interface IWriteOnlyRepository<T> {
  create(ctx: ServiceContext, data: Partial<T>): Promise<T>;

  createMany(ctx: ServiceContext, data: Partial<T>[]): Promise<T[]>;

  update(ctx: ServiceContext, id: string, data: Partial<T>): Promise<T | null>;

  updateMany(
    ctx: ServiceContext,
    criteria: Partial<T>,
    data: Partial<T>,
  ): Promise<number>;

  softDelete(ctx: ServiceContext, id: string): Promise<boolean>;

  hardDelete(ctx: ServiceContext, id: string): Promise<boolean>;

  deleteMany(ctx: ServiceContext, criteria: Partial<T>): Promise<number>;
}

/**
 * Create pagination meta from count and options
 */
export function createPaginationMeta(
  total: number,
  page: number,
  limit: number,
): PaginationMeta {
  const totalPages = Math.ceil(total / limit);
  return {
    total,
    page,
    limit,
    totalPages,
    hasNext: page < totalPages,
    hasPrev: page > 1,
  };
}
