import { Injectable, BadRequestException, NotFoundException, ForbiddenException, Optional } from '@nestjs/common';
import { KnowledgeBaseRepository } from './knowledge-base.repository';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { ContentSafetyService } from '../content-safety/content-safety.service';
import { StorageService } from '../../infrastructure/storage/storage.service';
import { MAX_KNOWLEDGE_BASE_COUNT } from './constants/knowledge-base.constants';
import { KnowledgeSourceRepository } from '../knowledge-source/knowledge-source.repository';
import { FilesService } from '../files/files.service';

@Injectable()
export class KnowledgeBaseService {
  constructor(
    private readonly repository: KnowledgeBaseRepository,
    private readonly prisma: PrismaService,
    private readonly storage: StorageService,
    private readonly sourceRepository: KnowledgeSourceRepository,
    private readonly filesService: FilesService,
    @Optional() private readonly safety?: ContentSafetyService,
  ) {}

  async create(userId: string, dto: any) {
    const count = await this.repository.countByUserId(userId);
    if (count >= MAX_KNOWLEDGE_BASE_COUNT) {
      throw new BadRequestException('知识库数量已达到上限');
    }
    if (dto.title) {
      const check = await this.safety?.check(dto.title, { userId, contentType: 'kb-title' });
      if (check && !check.safe) throw new ForbiddenException('知识库名称包含违规内容');
    }
    return this.enrichWithCoverUrl(await this.repository.create(userId, dto));
  }

  async findAll(userId: string, opts?: { page?: number; limit?: number; visibility?: string; ownerType?: string }) {
    const kbs = await this.repository.findAllByUserId(userId, opts);
    return Promise.all(kbs.map(kb => this.enrichWithCoverUrl(kb)));
  }

  private async enrichWithCoverUrl(kb: any) {
    if (kb.coverKey) {
      try {
        kb.coverUrl = await this.storage.getDownloadUrl(kb.coverKey, 86400);
      } catch {
        kb.coverUrl = null;
      }
    } else {
      kb.coverUrl = null;
    }
    return kb;
  }

  async findOne(userId: string, id: string) {
    const kb = await this.repository.findById(id);
    if (!kb || kb.deletedAt) throw new NotFoundException('知识库不存在');
    // 公开库允许任何人查看
    if (kb.visibility === 'public') return kb;
    // 私有库只能 owner 查看
    if (String(kb.userId) !== userId) throw new NotFoundException('知识库不存在');
    return kb;
  }

  async update(userId: string, id: string, dto: any) {
    const kb = await this.repository.findById(id);
    if (!kb || String(kb.userId) !== userId) {
      throw new NotFoundException('知识库不存在');
    }
    if (dto.title) {
      const check = await this.safety?.check(dto.title, { userId, contentType: 'kb-title' });
      if (check && !check.safe) throw new ForbiddenException('知识库名称包含违规内容');
    }
    return this.repository.update(id, dto);
  }

  async remove(userId: string, id: string) {
    const kb = await this.repository.findById(id);
    if (!kb || String(kb.userId) !== userId) {
      throw new NotFoundException('知识库不存在');
    }

    const fileSources = await this.sourceRepository.findFileSourcesByKnowledgeBase(id);
    for (const source of fileSources) {
      if (source.fileId) {
        await this.filesService.deleteFile(userId, source.fileId);
      }
    }
    await this.sourceRepository.softDeleteMany(fileSources.map(source => source.id));

    return this.repository.softDelete(id);
  }

  // ── Pin ──

  async togglePin(userId: string, id: string) {
    const kb = await this.repository.findById(id);
    if (!kb || String(kb.userId) !== userId) throw new NotFoundException('知识库不存在');
    return this.repository.togglePin(id, !kb.isPinned);
  }

  // ── Visibility ──

  async setVisibility(userId: string, id: string, visibility: string) {
    const kb = await this.repository.findById(id);
    if (!kb || String(kb.userId) !== userId) throw new NotFoundException('知识库不存在');
    if (!['private', 'public'].includes(visibility)) throw new BadRequestException('visibility 必须为 private 或 public');
    return this.repository.setVisibility(id, visibility);
  }

  // ── Subscribe ──

  async subscribe(userId: string, knowledgeBaseId: string) {
    const kb = await this.repository.findById(knowledgeBaseId);
    if (!kb || kb.deletedAt) throw new NotFoundException('知识库不存在');
    if (kb.visibility !== 'public') throw new BadRequestException('只能订阅公开知识库');
    if (kb.userId === userId) throw new BadRequestException('不能订阅自己的知识库');
    return this.repository.subscribe(userId, knowledgeBaseId);
  }

  async unsubscribe(userId: string, knowledgeBaseId: string) {
    return this.repository.unsubscribe(userId, knowledgeBaseId);
  }

  async listSubscribed(userId: string, opts?: { page?: number; limit?: number }) {
    const kbs = await this.repository.findSubscribed(userId, opts);
    return Promise.all(kbs.map(kb => this.enrichWithCoverUrl(kb)));
  }

  // ── Discover ──

  async discoverPublic(opts?: { page?: number; limit?: number; search?: string }) {
    const kbs = await this.repository.findAllPublic(opts);
    return Promise.all(kbs.map(kb => this.enrichWithCoverUrl(kb)));
  }

  // ── Folder CRUD ──

  async createFolder(userId: string, kbId: string, dto: { name: string; parentId?: string }) {
    const kb = await this.repository.findById(kbId);
    if (!kb || kb.deletedAt) throw new NotFoundException('知识库不存在');
    if (String(kb.userId) !== userId) throw new ForbiddenException('无权操作该知识库');

    // Validate parent folder belongs to same KB
    if (dto.parentId) {
      const parentFolder = await this.prisma.knowledgeFolder.findUnique({ where: { id: dto.parentId } });
      if (!parentFolder || parentFolder.knowledgeBaseId !== kbId) {
        throw new BadRequestException('父文件夹不存在或不属于该知识库');
      }
    }

    const [folder] = await Promise.all([
      this.prisma.knowledgeFolder.create({
        data: { knowledgeBaseId: kbId, name: dto.name, parentId: dto.parentId || null },
      }),
      // Create corresponding KnowledgeItem so it shows in the iOS item list
      this.prisma.knowledgeItem.create({
        data: {
          userId: kb.userId,
          knowledgeBaseId: kbId,
          title: dto.name,
          itemType: 'folder',
          parentId: dto.parentId || null,
          orderIndex: 0,
        },
      }),
    ]);
    return folder;
  }

  async getFolders(kbId: string) {
    return this.prisma.knowledgeFolder.findMany({
      where: { knowledgeBaseId: kbId, deletedAt: null },
      orderBy: { sortOrder: 'asc' },
    });
  }

  async updateFolder(folderId: string, dto: { name?: string; parentId?: string | null }) {
    return this.prisma.knowledgeFolder.update({ where: { id: folderId }, data: dto });
  }

  async deleteFolder(folderId: string) {
    const folder = await this.prisma.knowledgeFolder.findUnique({ where: { id: folderId } });
    if (!folder) throw new NotFoundException('文件夹不存在');

    // Soft-delete folder and children
    await this.prisma.knowledgeFolder.updateMany({
      where: { OR: [{ id: folderId }, { parentId: folderId }] },
      data: { deletedAt: new Date() },
    });

    // Also soft-delete the corresponding KnowledgeItem (itemType='folder')
    await this.prisma.knowledgeItem.updateMany({
      where: {
        knowledgeBaseId: folder.knowledgeBaseId,
        title: folder.name,
        itemType: 'folder',
        deletedAt: null,
      },
      data: { deletedAt: new Date() },
    });

    return { success: true };
  }
}
