import { eq, desc, asc } from "drizzle-orm";
import type { Db } from "@paperclipai/db";
import { chatFiles, chatFileReferences } from "@paperclipai/db";

const CODE_MIME_TYPES = new Set([
  "text/javascript",
  "text/typescript",
  "application/javascript",
  "application/typescript",
  "text/css",
  "text/html",
  "application/json",
  "text/x-python",
  "text/x-java",
  "text/x-c",
  "text/x-cpp",
  "text/x-csharp",
  "text/x-ruby",
  "text/x-go",
  "text/x-rust",
  "text/x-swift",
  "text/x-kotlin",
  "text/x-php",
  "text/x-shellscript",
  "application/x-sh",
  "text/x-yaml",
  "application/x-yaml",
  "text/x-toml",
]);

const DOCUMENT_MIME_TYPES = new Set([
  "application/pdf",
  "text/plain",
  "text/markdown",
  "text/csv",
]);

export function deriveCategory(mimeType: string): string {
  const mt = mimeType.toLowerCase();
  if (mt.startsWith("image/")) return "image";
  if (CODE_MIME_TYPES.has(mt)) return "code";
  if (DOCUMENT_MIME_TYPES.has(mt)) return "document";
  return "other";
}

export function chatFileService(db: Db) {
  return {
    create(
      companyId: string,
      data: Omit<typeof chatFiles.$inferInsert, "companyId" | "id" | "createdAt" | "updatedAt">,
    ) {
      return db
        .insert(chatFiles)
        .values({ ...data, companyId })
        .returning()
        .then((rows) => rows[0]!);
    },

    getById(id: string) {
      return db
        .select()
        .from(chatFiles)
        .where(eq(chatFiles.id, id))
        .then((rows) => rows[0] ?? null);
    },

    listByConversation(conversationId: string, opts?: { limit?: number }) {
      const limit = opts?.limit ?? 50;
      return db
        .select()
        .from(chatFiles)
        .where(eq(chatFiles.conversationId, conversationId))
        .orderBy(desc(chatFiles.createdAt))
        .limit(limit);
    },

    listByMessage(messageId: string) {
      return db
        .select()
        .from(chatFiles)
        .where(eq(chatFiles.messageId, messageId))
        .orderBy(asc(chatFiles.createdAt));
    },

    createReference(data: {
      fileId: string;
      conversationId: string;
      messageId?: string;
    }) {
      return db
        .insert(chatFileReferences)
        .values(data)
        .returning()
        .then((rows) => rows[0]!);
    },

    listReferences(fileId: string) {
      return db
        .select()
        .from(chatFileReferences)
        .where(eq(chatFileReferences.fileId, fileId));
    },

    attachToMessage(fileId: string, messageId: string) {
      return db
        .update(chatFiles)
        .set({ messageId, updatedAt: new Date() })
        .where(eq(chatFiles.id, fileId))
        .returning()
        .then((rows) => rows[0]!);
    },

    promoteToProject(fileId: string, projectId: string) {
      return db
        .update(chatFiles)
        .set({ projectId, updatedAt: new Date() })
        .where(eq(chatFiles.id, fileId))
        .returning()
        .then((rows) => rows[0] ?? null);
    },

    markAsPlaceholder(fileId: string) {
      return db
        .update(chatFiles)
        .set({ category: "placeholder", updatedAt: new Date() })
        .where(eq(chatFiles.id, fileId))
        .returning()
        .then((rows) => rows[0] ?? null);
    },
  };
}
