import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
import { Database } from 'bun:sqlite';
import { mkdtempSync, rmSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { startWebServer } from './helpers/server';
import { initializeDatabase, ensureUserExists } from '../../src/db';

import { sha256Hex } from '../helpers/crypto';

import { toIsoSql } from '../helpers/dates';

describe('Web API - GET /api/me/preferences', () => {
	const userId = '34600123456';
	let dbPath: string;
	let server: Awaited<ReturnType<typeof startWebServer>> | null = null;
	let tmpDir: string;

	beforeAll(async () => {
		tmpDir = mkdtempSync(join(tmpdir(), 'webtest-'));
		dbPath = join(tmpDir, 'tasks.db');

		// Inicializar DB en archivo (como en prod)
		const db = new Database(dbPath);
		initializeDatabase(db);
		ensureUserExists(userId, db);

		// Crear sesión válida
		const sid = 'sid-test-pref';
		const hash = await sha256Hex(sid);
		const now = new Date();
		const nowIso = toIsoSql(now);
		const expIso = toIsoSql(new Date(now.getTime() + 60 * 60 * 1000)); // +1h

		db.prepare(`
			INSERT INTO web_sessions (session_hash, user_id, created_at, last_seen_at, expires_at)
			VALUES (?, ?, ?, ?, ?)
		`).run(hash, userId, nowIso, nowIso, expIso);
		db.close();

		// Arrancar web apuntando a este DB
		server = await startWebServer({
			port: 19100,
			env: { DB_PATH: dbPath, TZ: 'UTC' }
		});

		// Probar que el endpoint responde (no asertivo aún)
		const res = await fetch(`${server.baseUrl}/api/me/preferences`, {
			headers: { Cookie: `sid=${sid}` }
		});
		expect(res.status).toBe(200);
	});

	afterAll(async () => {
		try { await server?.stop(); } catch {}
		try { rmSync(tmpDir, { recursive: true, force: true }); } catch {}
	});

	it('devuelve valores por defecto cuando no hay preferencias guardadas', async () => {
		const sid = 'sid-test-pref';
		const res = await fetch(`${server!.baseUrl}/api/me/preferences`, {
			headers: { Cookie: `sid=${sid}` }
		});
		expect(res.status).toBe(200);
		const json = await res.json();
		expect(json).toEqual({ freq: 'off', time: '08:30' });
	});

	it('POST /api/me/preferences - flujo completo', async () => {
		const sid = 'sid-test-pref';
		const base = server!.baseUrl;

		// 1) daily sin hora -> usa default '08:30'
		let res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'daily' })
		});
		expect(res.status).toBe(200);
		let json = await res.json();
		expect(json).toEqual({ freq: 'daily', time: '08:30' });

		// GET refleja lo guardado
		res = await fetch(`${base}/api/me/preferences`, { headers: { Cookie: `sid=${sid}` } });
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'daily', time: '08:30' });

		// 2) weekly con hora '7:5' → normaliza a '07:05'
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'weekly', time: '7:5' })
		});
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'weekly', time: '07:05' });

		// 3) weekdays con hora inválida → 400
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'weekdays', time: '25:00' })
		});
		expect(res.status).toBe(400);

		// 4) freq inválida → 400
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'foo', time: '08:00' })
		});
		expect(res.status).toBe(400);

		// 5) off sin hora → conserva última ('07:05')
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'off' })
		});
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'off', time: '07:05' });

		// GET refleja off con hora conservada
		res = await fetch(`${base}/api/me/preferences`, { headers: { Cookie: `sid=${sid}` } });
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'off', time: '07:05' });

		// 6) weekdays con hora válida
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'weekdays', time: '18:45' })
		});
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'weekdays', time: '18:45' });

		// 7) daily con hora '6:7' -> normaliza '06:07'
		res = await fetch(`${base}/api/me/preferences`, {
			method: 'POST',
			headers: { 'content-type': 'application/json', Cookie: `sid=${sid}` },
			body: JSON.stringify({ freq: 'daily', time: '6:7' })
		});
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'daily', time: '06:07' });

		// GET final
		res = await fetch(`${base}/api/me/preferences`, { headers: { Cookie: `sid=${sid}` } });
		expect(res.status).toBe(200);
		json = await res.json();
		expect(json).toEqual({ freq: 'daily', time: '06:07' });
	});
});
