import crypto from "node:crypto";
import path from "node:path";
import { fileURLToPath } from "node:url";
import request from "supertest";
import { newDb } from "pg-mem";
import { createApp } from "../server/app.js";

export const root = path.resolve(
	path.dirname(fileURLToPath(import.meta.url)),
	"..",
);
export const password = "this is a long password";

export async function setup(env = {}, appOptions = {}) {
	const mem = newDb();
	mem.public.registerFunction({
		name: "gen_random_uuid",
		returns: "uuid",
		implementation: () => crypto.randomUUID(),
		impure: true,
	});
	const pg = mem.adapters.createPg();
	const db = new pg.Pool();
	await db.query(
		`CREATE TABLE users(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),email text UNIQUE NOT NULL,password_hash text NOT NULL,role text NOT NULL DEFAULT 'user',created_at timestamptz DEFAULT now(),disabled_at timestamptz,avatar text);
		 CREATE TABLE sessions(token_hash text PRIMARY KEY,user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,csrf_hash text NOT NULL,expires_at timestamptz NOT NULL,created_at timestamptz DEFAULT now(),user_agent text,ip text,last_seen_at timestamptz);
		 CREATE TABLE roast_plans(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,plan jsonb NOT NULL,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE app_settings(key text PRIMARY KEY,value text NOT NULL);
		 INSERT INTO app_settings VALUES('signup_enabled','true');
		 INSERT INTO app_settings VALUES('llm_model','');
		 CREATE TABLE password_reset_tokens(token_hash text PRIMARY KEY,user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,expires_at timestamptz NOT NULL,created_at timestamptz DEFAULT now());
		 CREATE TABLE audit_events(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),actor_user_id uuid REFERENCES users(id) ON DELETE SET NULL,action text NOT NULL,target text,created_at timestamptz DEFAULT now());
		 CREATE TABLE green_bean_lots(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,origin text NOT NULL,variety text NOT NULL DEFAULT '',process text NOT NULL DEFAULT '',producer text NOT NULL DEFAULT '',purchase_date date,initial_weight_g numeric NOT NULL,remaining_weight_g numeric NOT NULL,cost_total numeric,moisture_pct numeric,density_g_l numeric,notes text NOT NULL DEFAULT '',archived boolean NOT NULL DEFAULT false,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE bean_consumption(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),lot_id uuid NOT NULL REFERENCES green_bean_lots(id) ON DELETE CASCADE,user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,weight_g numeric NOT NULL CHECK (weight_g > 0),created_at timestamptz DEFAULT now());
		 CREATE UNIQUE INDEX bean_consumption_one_per_plan ON bean_consumption(roast_plan_id);
		 CREATE TABLE cupping_sessions(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,data jsonb NOT NULL,total_score numeric NOT NULL DEFAULT 0,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE roasters(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,name text NOT NULL,model text NOT NULL DEFAULT '',notes text NOT NULL DEFAULT '',is_default boolean NOT NULL DEFAULT false,overrides jsonb NOT NULL DEFAULT '{}',created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE actual_roasts(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,roaster_id uuid REFERENCES roasters(id) ON DELETE SET NULL,filename text NOT NULL,original_content text NOT NULL,parsed jsonb NOT NULL,after jsonb NOT NULL DEFAULT '{}',evaluation jsonb,evaluation_status text NOT NULL DEFAULT 'pending',evaluation_error text,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE roasted_beans(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,name text NOT NULL,roaster text NOT NULL DEFAULT '',origin text NOT NULL DEFAULT '',process text NOT NULL DEFAULT '',variety text NOT NULL DEFAULT '',roast_level text NOT NULL DEFAULT '',roast_date date,initial_weight_g numeric,url text NOT NULL DEFAULT '',tasting_notes text NOT NULL DEFAULT '',notes text NOT NULL DEFAULT '',roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,archived boolean NOT NULL DEFAULT false,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE brews(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,bean_id uuid REFERENCES roasted_beans(id) ON DELETE SET NULL,method text NOT NULL,dose_g numeric,water_g numeric,yield_g numeric,grinder text NOT NULL DEFAULT '',grind_setting text NOT NULL DEFAULT '',water_temp_c numeric,brew_time_s integer,bloom_time_s integer,rating numeric,recipe text NOT NULL DEFAULT '',tasting_notes text NOT NULL DEFAULT '',notes text NOT NULL DEFAULT '',brewed_at timestamptz DEFAULT now(),created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now());
		 CREATE TABLE api_tokens(token_hash text PRIMARY KEY,user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,name text NOT NULL DEFAULT '',created_at timestamptz DEFAULT now(),last_used_at timestamptz);
		 CREATE TABLE user_gear(user_id uuid PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,brewers jsonb NOT NULL DEFAULT '[]',grinders jsonb NOT NULL DEFAULT '[]',updated_at timestamptz DEFAULT now())`,
	);
	const app = createApp({
		db,
		root,
		env: {
			NODE_ENV: "test",
			BOOTSTRAP_SETUP_TOKEN: "a-secure-bootstrap-token",
			...env,
		},
		...appOptions,
	});
	return { db, app, agent: request.agent(app) };
}

export async function signup(agent, email) {
	const response = await agent.post("/api/auth/signup").send({ email, password });
	return { response, csrf: response.body.csrfToken };
}
