import { Injectable } from "@nestjs/common";
import { Prisma } from "@prisma/client";
import { PrismaService } from "../../prisma/prisma.service";
import { LinkResolutionService } from "./link-resolution.service";
import { parseWikiLinks } from "../utils/wiki-link-parser";

/**
 * Represents a backlink to a knowledge entry
 */
export interface Backlink {
  id: string;
  sourceId: string;
  targetId: string;
  linkText: string;
  displayText: string;
  positionStart: number;
  positionEnd: number;
  resolved: boolean;
  context: string | null;
  createdAt: Date;
  source: {
    id: string;
    title: string;
    slug: string;
  };
}

/**
 * Represents an unresolved wiki link
 */
export interface UnresolvedLink {
  id: string;
  sourceId: string;
  targetId: string | null;
  linkText: string;
  displayText: string;
  positionStart: number;
  positionEnd: number;
  resolved: boolean;
  context: string | null;
  createdAt: Date;
  source: {
    id: string;
    title: string;
    slug: string;
  };
}

/**
 * Service for synchronizing wiki-style links in knowledge entries
 *
 * Responsibilities:
 * - Parse content for wiki links
 * - Resolve links to knowledge entries
 * - Store/update link records
 * - Handle orphaned links
 */
@Injectable()
export class LinkSyncService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly linkResolver: LinkResolutionService
  ) {}

  /**
   * Sync links for a knowledge entry
   * Parses content, resolves links, and updates the database
   *
   * @param workspaceId - The workspace scope
   * @param entryId - The entry being updated
   * @param content - The markdown content to parse
   */
  async syncLinks(workspaceId: string, entryId: string, content: string): Promise<void> {
    // Parse wiki links from content
    const parsedLinks = parseWikiLinks(content);

    // Get existing links for this entry
    const existingLinks = await this.prisma.knowledgeLink.findMany({
      where: {
        sourceId: entryId,
      },
    });

    // Resolve all parsed links
    const linkCreations: Prisma.KnowledgeLinkUncheckedCreateInput[] = [];

    for (const link of parsedLinks) {
      const targetId = await this.linkResolver.resolveLink(workspaceId, link.target);

      // Only create link record if targetId was resolved
      // (Schema requires targetId to be non-null)
      if (targetId) {
        linkCreations.push({
          sourceId: entryId,
          targetId,
          linkText: link.target,
          displayText: link.displayText,
          positionStart: link.start,
          positionEnd: link.end,
          resolved: true,
        });
      }
    }

    // Determine which existing links to keep/delete
    // We'll use a simple strategy: delete all existing and recreate
    // (In production, you might want to diff and only update changed links)
    const existingLinkIds = existingLinks.map((link) => link.id);

    // Delete all existing links and create new ones in a transaction
    await this.prisma.$transaction(async (tx) => {
      // Delete all existing links
      if (existingLinkIds.length > 0) {
        await tx.knowledgeLink.deleteMany({
          where: {
            sourceId: entryId,
            id: {
              in: existingLinkIds,
            },
          },
        });
      }

      // Create new links
      for (const linkData of linkCreations) {
        await tx.knowledgeLink.create({
          data: linkData,
        });
      }
    });
  }

  /**
   * Get all backlinks for an entry
   * Returns entries that link TO this entry
   *
   * @param entryId - The target entry
   * @returns Array of backlinks with source entry information
   */
  async getBacklinks(entryId: string): Promise<Backlink[]> {
    const backlinks = await this.prisma.knowledgeLink.findMany({
      where: {
        targetId: entryId,
        resolved: true,
      },
      include: {
        source: {
          select: {
            id: true,
            title: true,
            slug: true,
          },
        },
      },
      orderBy: {
        createdAt: "desc",
      },
    });

    return backlinks as Backlink[];
  }

  /**
   * Get all unresolved links for a workspace
   * Useful for finding broken links or pages that need to be created
   *
   * @param workspaceId - The workspace scope
   * @returns Array of unresolved links
   */
  async getUnresolvedLinks(workspaceId: string): Promise<UnresolvedLink[]> {
    const unresolvedLinks = await this.prisma.knowledgeLink.findMany({
      where: {
        source: {
          workspaceId,
        },
        resolved: false,
      },
      include: {
        source: {
          select: {
            id: true,
            title: true,
            slug: true,
          },
        },
      },
    });

    return unresolvedLinks as UnresolvedLink[];
  }
}
