import { and, eq } from 'drizzle-orm';

import { db } from '@/lib/db';
import { savedViews } from '@/lib/db/schema';
import { NotFoundError } from '@/lib/errors';
import type { CreateSavedViewInput, UpdateSavedViewInput } from '@/lib/validators/saved-views';

export const savedViewsService = {
  async list(portId: string, userId: string, entityType?: string) {
    const conditions = [eq(savedViews.portId, portId), eq(savedViews.userId, userId)];
    if (entityType) {
      conditions.push(eq(savedViews.entityType, entityType));
    }
    return db
      .select()
      .from(savedViews)
      .where(and(...conditions));
  },

  async create(portId: string, userId: string, data: CreateSavedViewInput) {
    if (data.isDefault) {
      await db
        .update(savedViews)
        .set({ isDefault: false })
        .where(
          and(
            eq(savedViews.portId, portId),
            eq(savedViews.userId, userId),
            eq(savedViews.entityType, data.entityType),
            eq(savedViews.isDefault, true),
          ),
        );
    }

    const [view] = await db
      .insert(savedViews)
      .values({
        portId,
        userId,
        entityType: data.entityType,
        name: data.name,
        filters: data.filters ?? {},
        sortConfig: data.sortConfig ?? null,
        columnConfig: data.columnConfig ?? null,
        isShared: data.isShared ?? false,
        isDefault: data.isDefault ?? false,
      })
      .returning();

    return view;
  },

  async update(portId: string, userId: string, viewId: string, data: UpdateSavedViewInput) {
    const existing = await db.query.savedViews.findFirst({
      where: and(
        eq(savedViews.id, viewId),
        eq(savedViews.portId, portId),
        eq(savedViews.userId, userId),
      ),
    });

    if (!existing) {
      throw new NotFoundError('Saved view');
    }

    if (data.isDefault) {
      const entityType = data.entityType ?? existing.entityType;
      await db
        .update(savedViews)
        .set({ isDefault: false })
        .where(
          and(
            eq(savedViews.portId, portId),
            eq(savedViews.userId, userId),
            eq(savedViews.entityType, entityType),
            eq(savedViews.isDefault, true),
          ),
        );
    }

    const [updated] = await db
      .update(savedViews)
      .set({
        ...(data.name !== undefined && { name: data.name }),
        ...(data.entityType !== undefined && { entityType: data.entityType }),
        ...(data.filters !== undefined && { filters: data.filters }),
        ...(data.sortConfig !== undefined && { sortConfig: data.sortConfig }),
        ...(data.columnConfig !== undefined && { columnConfig: data.columnConfig }),
        ...(data.isShared !== undefined && { isShared: data.isShared }),
        ...(data.isDefault !== undefined && { isDefault: data.isDefault }),
        updatedAt: new Date(),
      })
      .where(
        and(
          eq(savedViews.id, viewId),
          eq(savedViews.portId, portId),
          eq(savedViews.userId, userId),
        ),
      )
      .returning();

    return updated;
  },

  async delete(portId: string, userId: string, viewId: string) {
    const existing = await db.query.savedViews.findFirst({
      where: and(
        eq(savedViews.id, viewId),
        eq(savedViews.portId, portId),
        eq(savedViews.userId, userId),
      ),
    });

    if (!existing) {
      throw new NotFoundError('Saved view');
    }

    await db
      .delete(savedViews)
      .where(
        and(
          eq(savedViews.id, viewId),
          eq(savedViews.portId, portId),
          eq(savedViews.userId, userId),
        ),
      );
  },

  async setDefault(portId: string, userId: string, entityType: string, viewId: string) {
    const existing = await db.query.savedViews.findFirst({
      where: and(
        eq(savedViews.id, viewId),
        eq(savedViews.portId, portId),
        eq(savedViews.userId, userId),
        eq(savedViews.entityType, entityType),
      ),
    });

    if (!existing) {
      throw new NotFoundError('Saved view');
    }

    // Unset any existing default for this entityType + user + port
    await db
      .update(savedViews)
      .set({ isDefault: false })
      .where(
        and(
          eq(savedViews.portId, portId),
          eq(savedViews.userId, userId),
          eq(savedViews.entityType, entityType),
          eq(savedViews.isDefault, true),
        ),
      );

    const [updated] = await db
      .update(savedViews)
      .set({ isDefault: true, updatedAt: new Date() })
      .where(
        and(
          eq(savedViews.id, viewId),
          eq(savedViews.portId, portId),
          eq(savedViews.userId, userId),
        ),
      )
      .returning();

    return updated;
  },
};
