import { mkdir, rm, cp } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import { readdirSync } from 'node:fs';
import { createRouter } from '@@/create-router';
import { getUserProjectsDir } from '@@/data-path';
import {
  getAllDashboardState,
  upsertDashboard,
  deleteDashboard,
  upsertScreen,
  deleteScreen,
  upsertProject,
  deleteProject,
  upsertDefaults,
} from 'officerdb';

const TEMPLATES_DIR = resolve(import.meta.dir, '../../../../seed/project-templates');

export const dashboardsRouter = createRouter();

// GET /dashboards
dashboardsRouter.get('/', async (ctx) => {
  const userId = ctx.get('user').id;
  const state = await getAllDashboardState(userId);
  return ctx.json(state);
});

// PATCH /dashboards
dashboardsRouter.patch('/', async (ctx) => {
  const user = ctx.get('user');
  const userId = user.id;
  const body = ctx.get('body') as Record<string, unknown>;

  for (const [key, value] of Object.entries(body)) {
    // workspaces — array of dashboard definitions with ordering
    if (key === 'workspaces') {
      const workspaces = value as Array<{ id: string; name: string; [k: string]: unknown }>;
      for (let i = 0; i < workspaces.length; i++) {
        const ws = workspaces[i]!;
        const { id, name, ...config } = ws;
        await upsertDashboard(userId, id, { name, config, sortOrder: i });
      }
      continue;
    }

    // ws-layout-{id}
    const wsLayoutMatch = key.match(/^ws-layout-(.+)$/);
    if (wsLayoutMatch) {
      const id = wsLayoutMatch[1]!;
      if (value === null) {
        await deleteDashboard(userId, id);
      } else {
        await upsertDashboard(userId, id, { layout: value });
      }
      continue;
    }

    // ws-terminals-default / ws-host-terminals-default
    if (key === 'ws-terminals-default') {
      await upsertDefaults(userId, { terminals: value });
      continue;
    }
    if (key === 'ws-host-terminals-default') {
      await upsertDefaults(userId, { hostTerminals: value });
      continue;
    }

    // ws-terminals-{id}
    const wsTerminalsMatch = key.match(/^ws-terminals-(.+)$/);
    if (wsTerminalsMatch) {
      const id = wsTerminalsMatch[1]!;
      await upsertDashboard(userId, id, { terminals: value });
      continue;
    }

    // ws-host-terminals-{id}
    const wsHostTerminalsMatch = key.match(/^ws-host-terminals-(.+)$/);
    if (wsHostTerminalsMatch) {
      const id = wsHostTerminalsMatch[1]!;
      await upsertDashboard(userId, id, { hostTerminals: value });
      continue;
    }

    // screens/{name}
    const screensMatch = key.match(/^screens\/(.+)$/);
    if (screensMatch) {
      const name = screensMatch[1]!;
      if (value === null) {
        await deleteScreen(userId, name);
      } else {
        await upsertScreen(userId, name, { layout: value });
      }
      continue;
    }

    // proj-meta-{slug} — create/update/delete project
    const projMetaMatch = key.match(/^proj-meta-(.+)$/);
    if (projMetaMatch) {
      const slug = projMetaMatch[1]!;
      const projectDir = join(getUserProjectsDir(user.email), slug);

      if (value === null) {
        await deleteProject(userId, slug);
        await rm(projectDir, { recursive: true, force: true });
        continue;
      }

      const meta = value as Record<string, unknown>;
      const isNew = !(await Bun.file(join(projectDir, '.officerdev', 'meta.json')).exists());
      await upsertProject(userId, slug, { meta: value });

      if (isNew) {
        if (meta.projectType === 'app') {
          const templateDir = join(TEMPLATES_DIR, 'simple-app-template');
          const entries = readdirSync(templateDir);
          for (const entry of entries) {
            if (entry === '.git' || entry === '.officerdev') continue;
            await cp(join(templateDir, entry), join(projectDir, entry), { recursive: true });
          }
          const pkgPath = join(projectDir, 'package.json');
          const pkg = await Bun.file(pkgPath)
            .json()
            .catch(() => null);
          if (pkg) {
            pkg.name = slug;
            await Bun.write(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
          }
          const install = Bun.spawn(['bun', 'install'], { cwd: projectDir, stdout: 'ignore', stderr: 'ignore' });
          await install.exited;
        }
        const gitInit = Bun.spawn(['git', 'init', projectDir], { stdout: 'ignore', stderr: 'ignore' });
        await gitInit.exited;
      }
      continue;
    }

    // proj-layout-{slug}
    const projLayoutMatch = key.match(/^proj-layout-(.+)$/);
    if (projLayoutMatch) {
      const slug = projLayoutMatch[1]!;
      await upsertProject(userId, slug, { layout: value });
      continue;
    }

    // proj-terminals-{slug}
    const projTerminalsMatch = key.match(/^proj-terminals-(.+)$/);
    if (projTerminalsMatch) {
      const slug = projTerminalsMatch[1]!;
      await upsertProject(userId, slug, { terminals: value });
      continue;
    }

    // proj-host-terminals-{slug}
    const projHostTerminalsMatch = key.match(/^proj-host-terminals-(.+)$/);
    if (projHostTerminalsMatch) {
      const slug = projHostTerminalsMatch[1]!;
      await upsertProject(userId, slug, { hostTerminals: value });
      continue;
    }
  }

  const state = await getAllDashboardState(userId);
  return ctx.json(state);
});
