import { logger } from '@goodgo/logger';

import { prisma } from '../../config/database.config';
import { ConflictError } from '../../errors/http-error';
import { hasCode } from '../../utils/error-utils';
import { BaseRepository, IRepository } from '../common/repository';

// EN: Feature entity type from Prisma
// VI: Feature entity type từ Prisma
type Feature = {
  id: string;
  name: string;
  title: string | null;
  description: string | null;
  config: Record<string, unknown>;
  enabled: boolean;
  version: string | null;
  tags: string[];
  createdAt: Date;
  updatedAt: Date;
};

// EN: Input types for create/update operations
// VI: Input types cho create/update operations
type CreateFeatureInput = {
  name: string;
  title?: string;
  description?: string;
  config?: Record<string, unknown>;
  tags?: string[];
};

type UpdateFeatureInput = {
  title?: string;
  description?: string;
  config?: Record<string, unknown>;
  enabled?: boolean;
  tags?: string[];
};

/**
 * EN: Feature repository implementing repository pattern
 * VI: Feature repository implement repository pattern
 */
export class FeatureRepository extends BaseRepository<Feature, CreateFeatureInput, UpdateFeatureInput>
  implements IRepository<Feature, CreateFeatureInput, UpdateFeatureInput> {

  constructor() {
    super(prisma, 'feature');
  }

  /**
   * EN: Find feature by name (unique field)
   * VI: Tìm feature theo tên (field duy nhất)
   */
  async findByName(name: string): Promise<Feature | null> {
    return this.findByUnique('name', name);
  }

  /**
   * EN: Find features by tags
   * VI: Tìm features theo tags
   */
  async findByTags(tags: string[]): Promise<Feature[]> {
    try {
      logger.debug('Finding features by tags / Tìm features theo tags', { tags });

      // EN: Type assertion needed as Feature model may not exist in schema
      // VI: Cần type assertion vì Feature model có thể không tồn tại trong schema
      const features = await (this.prisma as any).feature.findMany({
        where: {
          tags: {
            hasSome: tags,
          },
        },
        orderBy: { createdAt: 'desc' },
      });

      logger.debug(`Found ${features.length} features by tags / Đã tìm thấy ${features.length} features theo tags`, { tags });
      return features;
    } catch (error) {
      logger.error('Failed to find features by tags / Không thể tìm features theo tags', { error, tags });
      throw this.handleDatabaseError(error, { tags });
    }
  }

  /**
   * EN: Find enabled features only
   * VI: Tìm chỉ features đã được bật
   */
  async findEnabled(): Promise<Feature[]> {
    try {
      logger.debug('Finding enabled features / Tìm features đã được bật');

      // EN: Type assertion needed as Feature model may not exist in schema
      // VI: Cần type assertion vì Feature model có thể không tồn tại trong schema
      const features = await (this.prisma as any).feature.findMany({
        where: { enabled: true },
        orderBy: { createdAt: 'desc' },
      });

      logger.debug(`Found ${features.length} enabled features / Đã tìm thấy ${features.length} features đã được bật`);
      return features;
    } catch (error) {
      logger.error('Failed to find enabled features / Không thể tìm features đã được bật', { error });
      throw this.handleDatabaseError(error);
    }
  }

  /**
   * EN: Create feature with duplicate name check
   * VI: Tạo feature với kiểm tra tên trùng lặp
   */
  async create(data: CreateFeatureInput): Promise<Feature> {
    try {
      // EN: Check for duplicate name
      // VI: Kiểm tra tên trùng lặp
      const existingFeature = await this.findByName(data.name);
      if (existingFeature) {
        logger.warn('Feature with this name already exists / Feature với tên này đã tồn tại', { name: data.name });
        throw new ConflictError('Feature with this name already exists / Feature với tên này đã tồn tại', { name: data.name });
      }

      return await super.create(data);
    } catch (error) {
      if (error instanceof ConflictError) {
        throw error;
      }
      throw error;
    }
  }

  /**
   * EN: Toggle feature enabled/disabled status
   * VI: Bật/tắt trạng thái feature
   */
  async toggleEnabled(id: string): Promise<Feature> {
    try {
      logger.debug('Toggling feature enabled status / Chuyển đổi trạng thái feature', { id });

      const feature = await this.findById(id);
      if (!feature) {
        throw new ConflictError('Feature not found / Feature không tìm thấy', { id });
      }

      const updatedFeature = await this.update(id, {
        enabled: !feature.enabled,
      });

      logger.debug(`Feature ${updatedFeature.enabled ? 'enabled' : 'disabled'} / Feature đã được ${updatedFeature.enabled ? 'bật' : 'tắt'}`, { id });
      return updatedFeature;
    } catch (error) {
      if (error instanceof ConflictError) {
        throw error;
      }
      logger.error('Failed to toggle feature status / Không thể chuyển đổi trạng thái feature', { error, id });
      throw this.handleDatabaseError(error, { id });
    }
  }

  /**
   * EN: Search features by name or description
   * VI: Tìm kiếm features theo tên hoặc mô tả
   */
  async search(query: string, limit: number = 10): Promise<Feature[]> {
    try {
      logger.debug('Searching features / Tìm kiếm features', { query, limit });

      // EN: Type assertion needed as Feature model may not exist in schema
      // VI: Cần type assertion vì Feature model có thể không tồn tại trong schema
      const features = await (this.prisma as any).feature.findMany({
        where: {
          OR: [
            { name: { contains: query, mode: 'insensitive' } },
            { title: { contains: query, mode: 'insensitive' } },
            { description: { contains: query, mode: 'insensitive' } },
          ],
        },
        take: limit,
        orderBy: { createdAt: 'desc' },
      });

      logger.debug(`Found ${features.length} features matching search / Đã tìm thấy ${features.length} features khớp với tìm kiếm`, { query });
      return features;
    } catch (error) {
      logger.error('Failed to search features / Không thể tìm kiếm features', { error, query });
      throw this.handleDatabaseError(error, { query });
    }
  }

  /**
   * EN: Get feature statistics
   * VI: Lấy thống kê feature
   */
  async getStatistics(): Promise<{
    total: number;
    enabled: number;
    disabled: number;
    byTag: Record<string, number>;
  }> {
    try {
      logger.debug('Getting feature statistics / Lấy thống kê feature');

      const [total, enabled, disabled, features] = await Promise.all([
        this.count(),
        this.count({ enabled: true }),
        this.count({ enabled: false }),
        this.findAll(),
      ]);

      // EN: Count by tags
      // VI: Đếm theo tags
      const byTag: Record<string, number> = {};
      features.forEach(feature => {
        feature.tags.forEach(tag => {
          byTag[tag] = (byTag[tag] || 0) + 1;
        });
      });

      const statistics = { total, enabled, disabled, byTag };
      logger.debug('Feature statistics retrieved / Thống kê feature đã được lấy', statistics);
      return statistics;
    } catch (error) {
      logger.error('Failed to get feature statistics / Không thể lấy thống kê feature', { error });
      throw this.handleDatabaseError(error);
    }
  }

  /**
   * EN: Handle database-specific errors
   * VI: Xử lý lỗi database-specific
   */
  private handleDatabaseError(error: unknown, context?: unknown) {
    if (hasCode(error) && error.code === 'P2002') {
      return new ConflictError('Feature with this name already exists / Feature với tên này đã tồn tại', context);
    }
    return error;
  }
}

// EN: Singleton instance
// VI: Singleton instance
export const featureRepository = new FeatureRepository();