/**
 * Expenses Domain Adapter
 *
 * Routes expenses and expense_categories to Convex.
 * These models exist ONLY in Convex (no Prisma models).
 *
 * When DS_EXPENSES=prisma (default), operations throw since there
 * are no Prisma tables. When DS_EXPENSES=convex, uses Convex backend.
 */

import { convexQuery, convexMutation } from "@/lib/convex-client";
import { getDataSource } from "@/lib/data-source";
import {
  convexToPrismaShapeMany,
  applyPagination,
  dateToConvexTimestamp,
  type ConvexDoc,
} from "./base";

const DOMAIN = "expenses" as const;
const EXPENSE_TS_FIELDS = ["createdAt", "updatedAt", "date"];
const CATEGORY_TS_FIELDS = ["createdAt", "updatedAt"];

function requireConvex(): void {
  if (getDataSource(DOMAIN) !== "convex") {
    throw new Error(
      "Expenses domain requires DS_EXPENSES=convex (no Prisma model exists)",
    );
  }
}

// ─── Expenses ───────────────────────────────────────────────────────────────

export const expensesAdapter = {
  async findMany(args: {
    where?: Record<string, unknown>;
    skip?: number;
    take?: number;
  }) {
    requireConvex();
    const filters = args.where || {};
    const docs =
      (await convexQuery<ConvexDoc[]>("expenses/queries:getExpenses", {
        userId: filters.userId as string,
        categoryId: filters.categoryId as string | undefined,
        limit: (args.skip ?? 0) + (args.take ?? 50) + 10,
      })) || [];
    const shaped = convexToPrismaShapeMany<Record<string, unknown>>(
      docs,
      EXPENSE_TS_FIELDS,
    );
    return applyPagination(shaped, args.skip, args.take);
  },

  async findFirst(args: { where?: Record<string, unknown> }) {
    requireConvex();
    const docs = await this.findMany({ where: args.where, take: 1 });
    return docs[0] || null;
  },

  async findUnique(args: { where: { id: string } }) {
    requireConvex();
    const docs = await this.findMany({ where: {} });
    return (
      docs.find((d: Record<string, unknown>) => d.id === args.where.id) || null
    );
  },

  async create(args: { data: Record<string, unknown> }) {
    requireConvex();
    const d = args.data;
    const convexId = await convexMutation<string>(
      "expenses/mutations:createExpense",
      {
        userId: d.userId as string,
        categoryId: d.categoryId as string,
        amount: d.amount as number,
        currency: d.currency as string | undefined,
        vendor: d.vendor as string | undefined,
        description: d.description as string | undefined,
        date: dateToConvexTimestamp(d.date as Date | string | number),
        receiptUrl: d.receiptUrl as string | undefined,
        isRecurring: d.isRecurring as boolean | undefined,
        recurringFrequency: d.recurringFrequency as string | undefined,
        tags: d.tags as string[] | undefined,
        notes: d.notes as string | undefined,
      },
    );
    return { ...d, id: d.id || convexId || "" };
  },

  async update(args: { where: { id: string }; data: Record<string, unknown> }) {
    requireConvex();
    const d = args.data;
    await convexMutation("expenses/mutations:updateExpense", {
      id: args.where.id,
      categoryId: d.categoryId as string | undefined,
      amount: d.amount as number | undefined,
      vendor: d.vendor as string | undefined,
      description: d.description as string | undefined,
      date: dateToConvexTimestamp(d.date as Date | string | number | undefined),
      receiptUrl: d.receiptUrl as string | undefined,
      tags: d.tags as string[] | undefined,
      notes: d.notes as string | undefined,
    });
    return { ...d, id: args.where.id };
  },

  async delete(args: { where: { id: string } }) {
    requireConvex();
    await convexMutation("expenses/mutations:deleteExpense", {
      id: args.where.id,
    });
    return { id: args.where.id };
  },

  async count(args?: { where?: Record<string, unknown> }) {
    requireConvex();
    const docs = await this.findMany({ where: args?.where });
    return docs.length;
  },
};

// ─── Expense Categories ─────────────────────────────────────────────────────

export const expenseCategoriesAdapter = {
  async findMany(args: { where?: Record<string, unknown> }) {
    requireConvex();
    const filters = args.where || {};
    const docs =
      (await convexQuery<ConvexDoc[]>("expenses/queries:getCategories", {
        userId: filters.userId as string,
      })) || [];
    return convexToPrismaShapeMany<Record<string, unknown>>(
      docs,
      CATEGORY_TS_FIELDS,
    );
  },

  async findUnique(args: { where: { id: string } }) {
    requireConvex();
    const docs = await this.findMany({ where: {} });
    return (
      docs.find((d: Record<string, unknown>) => d.id === args.where.id) || null
    );
  },

  async create(args: { data: Record<string, unknown> }) {
    requireConvex();
    const d = args.data;
    const convexId = await convexMutation<string>(
      "expenses/mutations:createCategory",
      {
        userId: d.userId as string,
        name: d.name as string,
        nameAr: d.nameAr as string | undefined,
        color: d.color as string,
        icon: d.icon as string | undefined,
        sortOrder: d.sortOrder as number | undefined,
      },
    );
    return { ...d, id: d.id || convexId || "" };
  },
};
