import { eq, and } from 'drizzle-orm';
import { db } from '../db';
import { dashboards, screens, projects, dashboardDefaults } from '../schema';

// ── Full state read ──

export async function getAllDashboardState(userId: number): Promise<Record<string, unknown>> {
  const result: Record<string, unknown> = {};

  const [dashRows, screenRows, projectRows, defaultsRow] = await Promise.all([
    db.select().from(dashboards).where(eq(dashboards.userId, userId)),
    db.select().from(screens).where(eq(screens.userId, userId)),
    db.select().from(projects).where(eq(projects.userId, userId)),
    db
      .select()
      .from(dashboardDefaults)
      .where(eq(dashboardDefaults.userId, userId))
      .then((rows) => rows[0]),
  ]);

  // Dashboards → workspaces array + per-dashboard keys
  if (dashRows.length > 0) {
    const sorted = [...dashRows].sort((a, b) => a.sortOrder - b.sortOrder);
    result['workspaces'] = sorted.map((d) => ({ id: d.id, name: d.name, ...(d.config as object) }));

    for (const d of dashRows) {
      result[`ws-layout-${d.id}`] = d.layout;
      result[`ws-terminals-${d.id}`] = d.terminals;
      result[`ws-host-terminals-${d.id}`] = d.hostTerminals;
    }
  }

  // Defaults
  if (defaultsRow) {
    result['ws-terminals-default'] = defaultsRow.terminals;
    result['ws-host-terminals-default'] = defaultsRow.hostTerminals;
  }

  // Screens
  for (const s of screenRows) {
    result[`screens/${s.name}`] = s.layout;
  }

  // Projects
  const projectList = projectRows.map((p) => ({
    ...(p.meta as object),
    id: p.slug,
    cwd: `/Projects/${p.slug}`,
  }));
  result['projects'] = projectList;

  for (const p of projectRows) {
    result[`proj-layout-${p.slug}`] = p.layout;
    result[`proj-terminals-${p.slug}`] = p.terminals;
    result[`proj-host-terminals-${p.slug}`] = p.hostTerminals;
  }

  return result;
}

// ── Dashboard CRUD ──

type UpsertDashboardData = {
  name?: string;
  config?: unknown;
  layout?: unknown;
  terminals?: unknown;
  hostTerminals?: unknown;
  sortOrder?: number;
};

export async function upsertDashboard(userId: number, id: string, data: UpsertDashboardData): Promise<void> {
  const now = new Date();
  const existing = await db
    .select()
    .from(dashboards)
    .where(and(eq(dashboards.userId, userId), eq(dashboards.id, id)))
    .then((rows) => rows[0]);

  if (existing) {
    const set: Record<string, unknown> = { updatedAt: now };
    if (data.name !== undefined) set.name = data.name;
    if (data.config !== undefined) set.config = data.config;
    if (data.layout !== undefined) set.layout = data.layout;
    if (data.terminals !== undefined) set.terminals = data.terminals;
    if (data.hostTerminals !== undefined) set.hostTerminals = data.hostTerminals;
    if (data.sortOrder !== undefined) set.sortOrder = data.sortOrder;
    await db.update(dashboards).set(set).where(eq(dashboards.id, id));
  } else {
    await db.insert(dashboards).values({
      id,
      userId,
      name: data.name ?? id,
      config: data.config ?? {},
      layout: data.layout ?? [],
      terminals: data.terminals ?? [],
      hostTerminals: data.hostTerminals ?? [],
      sortOrder: data.sortOrder ?? 0,
      createdAt: now,
      updatedAt: now,
    });
  }
}

export async function deleteDashboard(userId: number, id: string): Promise<void> {
  await db.delete(dashboards).where(and(eq(dashboards.userId, userId), eq(dashboards.id, id)));
}

// ── Screen CRUD ──

type UpsertScreenData = {
  layout?: unknown;
  terminals?: unknown;
  hostTerminals?: unknown;
};

export async function upsertScreen(userId: number, name: string, data: UpsertScreenData): Promise<void> {
  const now = new Date();
  const set: Record<string, unknown> = { updatedAt: now };
  if (data.layout !== undefined) set.layout = data.layout;
  if (data.terminals !== undefined) set.terminals = data.terminals;
  if (data.hostTerminals !== undefined) set.hostTerminals = data.hostTerminals;

  await db
    .insert(screens)
    .values({
      userId,
      name,
      layout: (data.layout ?? []) as never,
      terminals: (data.terminals ?? {}) as never,
      hostTerminals: (data.hostTerminals ?? {}) as never,
      updatedAt: now,
    })
    .onConflictDoUpdate({
      target: [screens.userId, screens.name],
      set,
    });
}

export async function deleteScreen(userId: number, name: string): Promise<void> {
  await db.delete(screens).where(and(eq(screens.userId, userId), eq(screens.name, name)));
}

// ── Project CRUD ──

type UpsertProjectData = {
  meta?: unknown;
  layout?: unknown;
  terminals?: unknown;
  hostTerminals?: unknown;
};

export async function upsertProject(userId: number, slug: string, data: UpsertProjectData): Promise<void> {
  const now = new Date();
  const existing = await db
    .select()
    .from(projects)
    .where(and(eq(projects.userId, userId), eq(projects.slug, slug)))
    .then((rows) => rows[0]);

  if (existing) {
    const set: Record<string, unknown> = { updatedAt: now };
    if (data.meta !== undefined) set.meta = data.meta;
    if (data.layout !== undefined) set.layout = data.layout;
    if (data.terminals !== undefined) set.terminals = data.terminals;
    if (data.hostTerminals !== undefined) set.hostTerminals = data.hostTerminals;
    await db
      .update(projects)
      .set(set)
      .where(and(eq(projects.userId, userId), eq(projects.slug, slug)));
  } else {
    await db.insert(projects).values({
      userId,
      slug,
      meta: (data.meta ?? {}) as never,
      layout: (data.layout ?? []) as never,
      terminals: (data.terminals ?? []) as never,
      hostTerminals: (data.hostTerminals ?? {}) as never,
      createdAt: now,
      updatedAt: now,
    });
  }
}

export async function deleteProject(userId: number, slug: string): Promise<void> {
  await db.delete(projects).where(and(eq(projects.userId, userId), eq(projects.slug, slug)));
}

// ── Defaults ──

type UpsertDefaultsData = {
  terminals?: unknown;
  hostTerminals?: unknown;
};

export async function getDefaults(userId: number): Promise<{ terminals: unknown; hostTerminals: unknown }> {
  const [row] = await db.select().from(dashboardDefaults).where(eq(dashboardDefaults.userId, userId));
  return { terminals: row?.terminals ?? {}, hostTerminals: row?.hostTerminals ?? {} };
}

export async function upsertDefaults(userId: number, data: UpsertDefaultsData): Promise<void> {
  const now = new Date();
  const set: Record<string, unknown> = { updatedAt: now };
  if (data.terminals !== undefined) set.terminals = data.terminals;
  if (data.hostTerminals !== undefined) set.hostTerminals = data.hostTerminals;

  await db
    .insert(dashboardDefaults)
    .values({
      userId,
      terminals: (data.terminals ?? {}) as never,
      hostTerminals: (data.hostTerminals ?? {}) as never,
      updatedAt: now,
    })
    .onConflictDoUpdate({
      target: dashboardDefaults.userId,
      set,
    });
}
