import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { RedisService } from '../../infrastructure/redis/redis.service';
import { QueueService } from '../../infrastructure/queue/queue.service';
import { enrichWithNames } from '../../common/helpers/name-resolver';

const SW_CACHE_KEY = 'safety:words';
const SW_CACHE_TTL = 300;

@Injectable()
export class ContentSafetyService {
  private readonly logger = new Logger(ContentSafetyService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly redis: RedisService,
    private readonly queue: QueueService,
  ) {}

  async check(text: string, context: { userId?: string; contentType: string }): Promise<{ safe: boolean; riskLevel: string; matchedWords: string[] }> {
    if (!text) return { safe: true, riskLevel: 'low', matchedWords: [] };

    const words = await this.getSensitiveWords();
    const matched: string[] = [];
    let highestRisk = 'low';

    for (const sw of words) {
      if (text.includes(sw.word)) {
        matched.push(sw.word);
        if (sw.riskLevel === 'critical') highestRisk = 'critical';
        else if (sw.riskLevel === 'high' && highestRisk !== 'critical') highestRisk = 'high';
        else if (sw.riskLevel === 'medium' && highestRisk === 'low') highestRisk = 'medium';
      }
    }

    const result = highestRisk === 'critical' || highestRisk === 'high' ? 'blocked' : highestRisk === 'medium' ? 'flagged' : 'passed';

    // Save check record
    await this.prisma.contentSafetyCheck.create({
      data: {
        userId: context.userId || null,
        contentType: context.contentType,
        content: text.slice(0, 1000),
        riskLevel: highestRisk,
        matchedWords: matched.join(',') || null,
        result,
      },
    });

    return { safe: result !== 'blocked', riskLevel: highestRisk, matchedWords: matched };
  }

  private async getSensitiveWords(): Promise<{ word: string; riskLevel: string }[]> {
    try {
      const cached = await this.redis.get(SW_CACHE_KEY);
      if (cached) return JSON.parse(cached);
    } catch {}

    const words = await this.prisma.sensitiveWord.findMany({
      where: { enabled: true },
      select: { word: true, riskLevel: true },
    });

    try { await this.redis.set(SW_CACHE_KEY, JSON.stringify(words), SW_CACHE_TTL); } catch {}

    return words;
  }

  async addWord(word: string, category: string, riskLevel: string) {
    await this.prisma.sensitiveWord.create({ data: { word, category, riskLevel } });
    try { await this.redis.del(SW_CACHE_KEY); } catch {}
  }

  async removeWord(id: string) {
    await this.prisma.sensitiveWord.delete({ where: { id } });
    try { await this.redis.del(SW_CACHE_KEY); } catch {}
  }

  async getAllWords() { return this.prisma.sensitiveWord.findMany({ orderBy: { createdAt: 'desc' } }) }
  async getChecks(limit = 50) {
    const items = await this.prisma.contentSafetyCheck.findMany({ orderBy: { createdAt: 'desc' }, take: limit });
    return enrichWithNames(this.prisma, items);
  }

  // ── Reports ──

  async submitReport(input: { reporterId: string; targetType: string; targetId: string; reason: string }) {
    return this.prisma.contentReport.create({ data: input });
  }

  async getReports(status?: string) {
    return this.prisma.contentReport.findMany({
      where: status ? { status } : undefined,
      orderBy: { createdAt: 'desc' },
      take: 100,
    });
  }

  async handleReport(id: string, action: string, note?: string) {
    const report = await this.prisma.contentReport.update({
      where: { id },
      data: { status: action, handleNote: note || null, handledAt: new Date() },
    });

    // If confirmed violation, create violation record
    if (action === 'confirmed') {
      await this.prisma.violationRecord.create({
        data: {
          userId: report.reporterId,
          contentType: report.targetType,
          content: report.reason,
          riskLevel: 'medium',
        },
      });
    }

    return report;
  }

  // ── Violations ──

  async getViolations(userId?: string, limit = 50) {
    return this.prisma.violationRecord.findMany({
      where: userId ? { userId } : undefined,
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  async applyPenalty(id: string, penalty: string) {
    return this.prisma.violationRecord.update({
      where: { id },
      data: { penalty, appliedAt: new Date() },
    });
  }
}
