import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  ParseIntPipe,
  DefaultValuePipe,
} from "@nestjs/common";
import type { AuthUser } from "@mosaic/shared";
import { EntryStatus } from "@prisma/client";
import { KnowledgeService } from "./knowledge.service";
import { CreateEntryDto, UpdateEntryDto, EntryQueryDto, RestoreVersionDto } from "./dto";
import { AuthGuard } from "../auth/guards/auth.guard";
import { WorkspaceGuard, PermissionGuard } from "../common/guards";
import { Workspace, Permission, RequirePermission } from "../common/decorators";
import { CurrentUser } from "../auth/decorators/current-user.decorator";
import { LinkSyncService } from "./services/link-sync.service";
import { KnowledgeCacheService } from "./services/cache.service";

/**
 * Controller for knowledge entry endpoints
 * All endpoints require authentication and workspace context
 * Uses the new guard-based permission system
 */
@Controller("knowledge/entries")
@UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard)
export class KnowledgeController {
  constructor(
    private readonly knowledgeService: KnowledgeService,
    private readonly linkSync: LinkSyncService
  ) {}

  /**
   * GET /api/knowledge/entries
   * List all entries in the workspace with pagination and filtering
   * Requires: Any workspace member
   */
  @Get()
  @RequirePermission(Permission.WORKSPACE_ANY)
  async findAll(@Workspace() workspaceId: string, @Query() query: EntryQueryDto) {
    return this.knowledgeService.findAll(workspaceId, query);
  }

  /**
   * GET /api/knowledge/entries/:slug
   * Get a single entry by slug
   * Requires: Any workspace member
   */
  @Get(":slug")
  @RequirePermission(Permission.WORKSPACE_ANY)
  async findOne(@Workspace() workspaceId: string, @Param("slug") slug: string) {
    return this.knowledgeService.findOne(workspaceId, slug);
  }

  /**
   * POST /api/knowledge/entries
   * Create a new knowledge entry
   * Requires: MEMBER role or higher
   */
  @Post()
  @RequirePermission(Permission.WORKSPACE_MEMBER)
  async create(
    @Workspace() workspaceId: string,
    @CurrentUser() user: AuthUser,
    @Body() createDto: CreateEntryDto
  ) {
    return this.knowledgeService.create(workspaceId, user.id, createDto);
  }

  /**
   * PUT /api/knowledge/entries/:slug
   * Update an existing entry
   * Requires: MEMBER role or higher
   */
  @Put(":slug")
  @RequirePermission(Permission.WORKSPACE_MEMBER)
  async update(
    @Workspace() workspaceId: string,
    @Param("slug") slug: string,
    @CurrentUser() user: AuthUser,
    @Body() updateDto: UpdateEntryDto
  ) {
    return this.knowledgeService.update(workspaceId, slug, user.id, updateDto);
  }

  /**
   * DELETE /api/knowledge/entries/:slug
   * Soft delete an entry (sets status to ARCHIVED)
   * Requires: ADMIN role or higher
   */
  @Delete(":slug")
  @RequirePermission(Permission.WORKSPACE_ADMIN)
  async remove(
    @Workspace() workspaceId: string,
    @Param("slug") slug: string,
    @CurrentUser() user: AuthUser
  ) {
    await this.knowledgeService.remove(workspaceId, slug, user.id);
    return { message: "Entry archived successfully" };
  }

  /**
   * GET /api/knowledge/entries/:slug/backlinks
   * Get all backlinks for an entry
   * Requires: Any workspace member
   */
  @Get(":slug/backlinks")
  @RequirePermission(Permission.WORKSPACE_ANY)
  async getBacklinks(@Workspace() workspaceId: string, @Param("slug") slug: string) {
    // First find the entry to get its ID
    const entry = await this.knowledgeService.findOne(workspaceId, slug);

    // Get backlinks
    const backlinks = await this.linkSync.getBacklinks(entry.id);

    return {
      entry: {
        id: entry.id,
        slug: entry.slug,
        title: entry.title,
      },
      backlinks,
      count: backlinks.length,
    };
  }

  /**
   * GET /api/knowledge/entries/:slug/versions
   * List all versions for an entry with pagination
   * Requires: Any workspace member
   */
  @Get(":slug/versions")
  @RequirePermission(Permission.WORKSPACE_ANY)
  async getVersions(
    @Workspace() workspaceId: string,
    @Param("slug") slug: string,
    @Query("page", new DefaultValuePipe(1), ParseIntPipe) page: number,
    @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number
  ) {
    return this.knowledgeService.findVersions(workspaceId, slug, page, limit);
  }

  /**
   * GET /api/knowledge/entries/:slug/versions/:version
   * Get a specific version of an entry
   * Requires: Any workspace member
   */
  @Get(":slug/versions/:version")
  @RequirePermission(Permission.WORKSPACE_ANY)
  async getVersion(
    @Workspace() workspaceId: string,
    @Param("slug") slug: string,
    @Param("version", ParseIntPipe) version: number
  ) {
    return this.knowledgeService.findVersion(workspaceId, slug, version);
  }

  /**
   * POST /api/knowledge/entries/:slug/restore/:version
   * Restore a previous version of an entry
   * Requires: MEMBER role or higher
   */
  @Post(":slug/restore/:version")
  @RequirePermission(Permission.WORKSPACE_MEMBER)
  async restoreVersion(
    @Workspace() workspaceId: string,
    @Param("slug") slug: string,
    @Param("version", ParseIntPipe) version: number,
    @CurrentUser() user: AuthUser,
    @Body() restoreDto: RestoreVersionDto
  ) {
    return this.knowledgeService.restoreVersion(
      workspaceId,
      slug,
      version,
      user.id,
      restoreDto.changeNote
    );
  }
}

/**
 * Controller for knowledge embeddings endpoints
 */
@Controller("knowledge/embeddings")
@UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard)
export class KnowledgeEmbeddingsController {
  constructor(private readonly knowledgeService: KnowledgeService) {}

  /**
   * POST /api/knowledge/embeddings/batch
   * Batch generate embeddings for all entries in the workspace
   * Useful for populating embeddings for existing entries
   * Requires: ADMIN role or higher
   */
  @Post("batch")
  @RequirePermission(Permission.WORKSPACE_ADMIN)
  async batchGenerate(@Workspace() workspaceId: string, @Body() body: { status?: string }) {
    const status = body.status as EntryStatus | undefined;
    const result = await this.knowledgeService.batchGenerateEmbeddings(workspaceId, status);
    return {
      message: `Generated ${result.success.toString()} embeddings out of ${result.total.toString()} entries`,
      ...result,
    };
  }
}

/**
 * Controller for knowledge cache endpoints
 */
@Controller("knowledge/cache")
@UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard)
export class KnowledgeCacheController {
  constructor(private readonly cache: KnowledgeCacheService) {}

  /**
   * GET /api/knowledge/cache/stats
   * Get cache statistics (hits, misses, hit rate, etc.)
   * Requires: Any workspace member
   */
  @Get("stats")
  @RequirePermission(Permission.WORKSPACE_ANY)
  getStats() {
    return {
      enabled: this.cache.isEnabled(),
      stats: this.cache.getStats(),
    };
  }

  /**
   * POST /api/knowledge/cache/clear
   * Clear all caches for the workspace
   * Requires: ADMIN role or higher
   */
  @Post("clear")
  @RequirePermission(Permission.WORKSPACE_ADMIN)
  async clearCache(@Workspace() workspaceId: string) {
    await this.cache.clearWorkspaceCache(workspaceId);
    return { message: "Cache cleared successfully" };
  }

  /**
   * POST /api/knowledge/cache/stats/reset
   * Reset cache statistics
   * Requires: ADMIN role or higher
   */
  @Post("stats/reset")
  @RequirePermission(Permission.WORKSPACE_ADMIN)
  resetStats() {
    this.cache.resetStats();
    return { message: "Cache statistics reset successfully" };
  }
}
