import { mkdir, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { AppConfigService } from "../../apps/desktop/src/main/services/app-config.js";
import {
  EMPTY_PROJECT_INVENTORY_MESSAGE,
  createSessionForActiveProject,
  listSessionsForActiveProject,
  loadActiveProjectWorkspaceState,
  requireActiveProject
} from "../../apps/desktop/src/main/services/project-inventory-state.js";
import { ProjectStoreService } from "../../apps/desktop/src/main/services/project-store.js";

function assert(condition: unknown, message: string): asserts condition {
  if (!condition) {
    throw new Error(message);
  }
}

async function main(): Promise<void> {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = path.resolve(__dirname, "..", "..");
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "project-empty-inventory-smoke", "result.json"));
  const tempRoot = path.dirname(resultPath);
  const userDataPath = path.join(tempRoot, "user-data");

  await rm(tempRoot, { recursive: true, force: true });
  await mkdir(userDataPath, { recursive: true });

  const configService = new AppConfigService(userDataPath);
  await configService.load();

  const projectStore = new ProjectStoreService(configService);
  await projectStore.initialize();

  const initialState = await loadActiveProjectWorkspaceState(projectStore);
  assert(initialState.projects.length === 0, "Initial project inventory should be empty.");
  assert(initialState.currentProject === null, "Initial active project should be null.");
  assert(initialState.sessions.length === 0, "Initial session list should be empty.");
  assert(initialState.skills.length === 0, "Initial skill list should be empty.");

  const listedSessionsBeforeSync = await listSessionsForActiveProject(projectStore);
  assert(listedSessionsBeforeSync.length === 0, "Listing sessions without a project should return an empty array.");

  const requiredProjectFailure = await requireActiveProject(projectStore)
    .then(() => null)
    .catch((error) => error instanceof Error ? error.message : String(error));
  assert(requiredProjectFailure === EMPTY_PROJECT_INVENTORY_MESSAGE, "Active project guard did not return the expected pending-cloud message.");

  const createSessionFailure = await createSessionForActiveProject(projectStore, "Should Fail")
    .then(() => null)
    .catch((error) => error instanceof Error ? error.message : String(error));
  assert(createSessionFailure === EMPTY_PROJECT_INVENTORY_MESSAGE, "Session creation guard did not return the expected pending-cloud message.");

  const syncedProject = await projectStore.syncBundleProject({
    projectId: "cloud-owned-project",
    projectName: "Cloud Owned Project",
    version: "config-v1",
    ready: true,
    boundSkillIds: []
  });

  const syncedState = await loadActiveProjectWorkspaceState(projectStore);
  assert(syncedState.projects.length === 1, "Project inventory should contain the synced bundle-backed project.");
  assert(syncedState.currentProject?.id === syncedProject.id, "Synced bundle-backed project should become active when inventory was empty.");
  assert(syncedState.sessions.length === 1, "Loading workspace state for a new active project should materialize exactly one default session.");
  assert(syncedState.sessions[0]?.projectId === syncedProject.id, "Default session should be bound to the synced active project.");

  const createdSession = await createSessionForActiveProject(projectStore, "After Sync");
  const listedSessionsAfterSync = await listSessionsForActiveProject(projectStore);
  assert(createdSession.projectId === syncedProject.id, "Created session after bundle sync should be bound to the active project.");
  assert(listedSessionsAfterSync.some((session) => session.id === createdSession.id), "Created session after bundle sync should appear in the active session list.");

  const summary = {
    ok: true,
    userDataPath,
    emptyInventoryMessage: EMPTY_PROJECT_INVENTORY_MESSAGE,
    initialProjectCount: initialState.projects.length,
    initialSessionCount: initialState.sessions.length,
    requiredProjectFailure,
    createSessionFailure,
    syncedProjectId: syncedProject.id,
    syncedProjectCount: syncedState.projects.length,
    syncedDefaultSessionCount: syncedState.sessions.length,
    createdSessionId: createdSession.id,
    listedSessionCountAfterSync: listedSessionsAfterSync.length
  };

  await mkdir(path.dirname(resultPath), { recursive: true });
  await writeFile(resultPath, JSON.stringify(summary, null, 2), "utf8");
  console.log(JSON.stringify(summary, null, 2));
}

main().catch(async (error) => {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = path.resolve(__dirname, "..", "..");
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "project-empty-inventory-smoke", "result.json"));
  const failure = {
    ok: false,
    error: error instanceof Error ? error.stack ?? error.message : String(error)
  };

  await mkdir(path.dirname(resultPath), { recursive: true });
  await writeFile(resultPath, JSON.stringify(failure, null, 2), "utf8");
  console.error(failure.error);
  process.exitCode = 1;
});
