import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { TranslationsService } from '../translations/translations.service';
import { TranslationType } from '../../generated/prisma/client.js';

export interface FeatSearchParams {
  query?: string;
  featType?: string;
  className?: string;
  ancestryName?: string;
  skillName?: string;
  minLevel?: number;
  maxLevel?: number;
  rarity?: string;
  traits?: string[];
  page?: number;
  limit?: number;
}

@Injectable()
export class FeatsService {
  constructor(
    private prisma: PrismaService,
    private translationsService: TranslationsService,
  ) {}

  async search(params: FeatSearchParams) {
    const {
      query,
      featType,
      className,
      ancestryName,
      skillName,
      minLevel,
      maxLevel,
      rarity,
      traits,
      page = 1,
      limit = 20,
    } = params;

    const where: any = {};

    // Text search on name
    if (query) {
      where.OR = [
        { name: { contains: query, mode: 'insensitive' } },
        { nameGerman: { contains: query, mode: 'insensitive' } },
        { summary: { contains: query, mode: 'insensitive' } },
      ];
    }

    // Feat type filter
    if (featType) {
      where.featType = featType;
    }

    // Class filter
    if (className) {
      where.className = className;
    }

    // Ancestry filter
    if (ancestryName) {
      where.ancestryName = ancestryName;
    }

    // Skill filter
    if (skillName) {
      where.skillName = skillName;
    }

    // Level range filter
    if (minLevel !== undefined) {
      where.level = { ...where.level, gte: minLevel };
    }
    if (maxLevel !== undefined) {
      where.level = { ...where.level, lte: maxLevel };
    }

    // Rarity filter
    if (rarity) {
      where.rarity = rarity;
    }

    // Traits filter (must have all specified traits)
    if (traits && traits.length > 0) {
      where.traits = { hasEvery: traits };
    }

    const skip = (page - 1) * limit;

    const [items, total] = await Promise.all([
      this.prisma.feat.findMany({
        where,
        skip,
        take: limit,
        orderBy: [{ level: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.feat.count({ where }),
    ]);

    return {
      items,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  async findById(id: string) {
    const feat = await this.prisma.feat.findUnique({
      where: { id },
    });

    if (!feat) return null;

    // Generate translation on-demand if missing
    if (!feat.nameGerman || !feat.summaryGerman) {
      return this.ensureTranslation(feat);
    }

    return feat;
  }

  async findByName(name: string) {
    // Try exact match first
    let feat = await this.prisma.feat.findUnique({
      where: { name },
    });

    // If not found, try case-insensitive search
    if (!feat) {
      feat = await this.prisma.feat.findFirst({
        where: {
          OR: [
            { name: { equals: name, mode: 'insensitive' } },
            { nameGerman: { equals: name, mode: 'insensitive' } },
          ],
        },
      });
    }

    if (!feat) return null;

    // Generate translation on-demand if missing
    if (!feat.nameGerman || !feat.summaryGerman) {
      return this.ensureTranslation(feat);
    }

    return feat;
  }

  async getFeatTypes() {
    const result = await this.prisma.feat.groupBy({
      by: ['featType'],
      where: { featType: { not: null } },
      orderBy: { featType: 'asc' },
    });

    return result.map((r) => r.featType).filter(Boolean);
  }

  async getClasses() {
    const result = await this.prisma.feat.groupBy({
      by: ['className'],
      where: { className: { not: null } },
      orderBy: { className: 'asc' },
    });

    return result.map((r) => r.className).filter(Boolean);
  }

  async getAncestries() {
    const result = await this.prisma.feat.groupBy({
      by: ['ancestryName'],
      where: { ancestryName: { not: null } },
      orderBy: { ancestryName: 'asc' },
    });

    return result.map((r) => r.ancestryName).filter(Boolean);
  }

  async getTraits() {
    // Get all unique traits across all feats
    const feats = await this.prisma.feat.findMany({
      select: { traits: true },
      where: { traits: { isEmpty: false } },
    });

    const traitsSet = new Set<string>();
    feats.forEach((f) => f.traits.forEach((t) => traitsSet.add(t)));

    return Array.from(traitsSet).sort();
  }

  // Ensure a feat has German translations, generating them if needed
  private async ensureTranslation(feat: {
    id: string;
    name: string;
    summary?: string | null;
    nameGerman?: string | null;
    summaryGerman?: string | null;
  }) {
    try {
      const translation = await this.translationsService.getTranslation(
        TranslationType.FEAT,
        feat.name,
        feat.summary || undefined,
      );

      // Update the database with the translation
      const updated = await this.prisma.feat.update({
        where: { id: feat.id },
        data: {
          nameGerman: translation.germanName,
          summaryGerman: translation.germanDescription,
        },
      });

      return updated;
    } catch (error) {
      // If translation fails, return the original feat
      console.error(`Failed to translate feat ${feat.name}:`, error);
      return feat;
    }
  }

  // Get translation for a feat (with caching)
  async getTranslatedFeat(feat: { name: string; summary?: string | null }) {
    const translation = await this.translationsService.getTranslation(
      TranslationType.FEAT,
      feat.name,
      feat.summary || undefined,
    );

    return {
      nameGerman: translation.germanName,
      summaryGerman: translation.germanDescription,
    };
  }

  // Update feat with German translation
  async updateFeatTranslation(id: string) {
    const feat = await this.prisma.feat.findUnique({ where: { id } });
    if (!feat) return null;

    const translation = await this.getTranslatedFeat(feat);

    return this.prisma.feat.update({
      where: { id },
      data: {
        nameGerman: translation.nameGerman,
        summaryGerman: translation.summaryGerman,
      },
    });
  }
}
