import { BookProject, Chapter, Entity, Idea, WorkflowData, UserProfile } from '../types'; // --- CONFIGURATION --- const AUTH_API_ROOT = '/api/user-auth'; const DATA_API_ROOT = '/api/data'; const INSTANCE_ID = '54770_plumeia_db'; // --- HELPERS --- // --- HELPERS --- const getHeaders = () => { /*const token = localStorage.getItem('ncb_session_token'); const sessionData = localStorage.getItem('ncb_session_data'); console.log("[API] Token:", token); console.log("[API] Session Data:", sessionData);*/ const headers: Record = { 'Content-Type': 'application/json', 'X-Database-Instance': INSTANCE_ID, // 'credentials': 'include' }; /* if (token) { // Fallback standard auth //headers['Authorization'] = `Bearer ${token}`; // User-requested specific Cookie format // Note: Browsers typically block manual "Cookie" header setting in fetch. // This is implemented per user request, but relies on the environment allowing it // or using credentials: 'include' for actual cookies. let cookieString = `better-auth.session_token=${token}`; if (sessionData) { cookieString += `; better-auth.session_data=${sessionData}`; } headers['Cookie'] = cookieString; console.log("[API] Cookie:", cookieString); } // Debug headers console.log("[API] Generated Headers:", headers); */ return headers; }; /* const handleAuthResponse = async (res: Response) => { const data = await res.json(); console.log("[API] Auth Response:", data); if (!res.ok) { throw new Error(data.message || 'Authentication failed'); } // Token extraction strategy const token = data.user?.token || data.token || data.session?.token || data.auth_token || data.accessToken || data._token; // Extract session data if available (often needed for Better Auth) const sessionData = data.session_data || data.session?.data || data.user?.session_data; if (token) { console.log("[API] Token extracted and saved:", token); localStorage.setItem('ncb_session_token', token); if (sessionData) { console.log("[API] Session Data extracted and saved"); localStorage.setItem('ncb_session_data', sessionData); } } else { console.warn("[API] No token found in successful auth response!"); } return data; };*/ const handleAuthResponse = async (res: Response) => { const data = await res.json(); console.log("[API] Raw Response Data:", data); if (!res.ok) { throw new Error(data.message || 'Authentication failed'); } // --- LOGIQUE DES SETTEURS --- // 1. Extraction du Token (selon la structure Better-Auth) const token = data.session?.token || data.token; // 2. Extraction du Session Data // On prend l'objet session complet et on le stringifie pour le stockage const sessionData = data.session ? JSON.stringify(data.session) : null; if (token) { localStorage.setItem('ncb_session_token', token); console.log("[Auth] Token saved to LocalStorage"); } if (sessionData) { localStorage.setItem('ncb_session_data', sessionData); console.log("[Auth] Session Data saved to LocalStorage"); } return data; }; // --- AUTH SERVICE --- export const authService = { /*async getSession() { const token = localStorage.getItem('ncb_session_token'); // Note: Even if we use cookies, we keep token logic as fallback or for UI state // if (!token) return null; try { const url = `${AUTH_API_ROOT}/get-session?Instance=${INSTANCE_ID}`; console.log(`[API] GET session ${url}`); const res = await fetch(url, { method: 'GET', //headers: getHeaders(), credentials: 'include' // IMPORTANT: Send cookies }); if (!res.ok) { console.log(`[API] getSession failed with status: ${res.status}`); if (res.status === 401) { localStorage.removeItem('ncb_session_token'); } return null; } const data = await res.json(); console.log("[API] getSession success:", data); return data.user || data; } catch (err) { console.error("[Auth] getSession error:", err); return null; } },*/ async getSession() { console.log("[getSession] démarrage"); const token = localStorage.getItem('ncb_session_token'); try { const url = `${AUTH_API_ROOT}/get-session?Instance=${INSTANCE_ID}`; const headers: Record = { 'Content-Type': 'application/json', 'X-Database-Instance': INSTANCE_ID }; // Si on a un token mais pas encore la session complète, on l'envoie if (token) { headers['Cookie'] = `better-auth.session_token=${token}`; // On peut aussi essayer le header Authorization au cas où headers['Authorization'] = `Bearer ${token}`; } const res = await fetch(url, { method: 'GET', headers: headers, credentials: 'include' }); if (res.ok) { const data = await res.json(); console.log("[getSession] getSession success:", data); // --- LES SETTEURS ICI --- if (data.session) { localStorage.setItem('ncb_session_token', data.session.token); localStorage.setItem('ncb_session_data', JSON.stringify(data.session)); console.log("[getSession] Données récupérées depuis getSession"); } return data.user || data; } return null; } catch (err) { console.error("[Auth] getSession error:", err); return null; } }, async signIn(email: string, password: string) { try { // Force X-Database-Instance header as URL param is insufficient for some NCB versions const url = `${AUTH_API_ROOT}/sign-in/email?Instance=${INSTANCE_ID}`; console.log(`[API] POST ${url}`, { email, password: '***' }); const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Database-Instance': INSTANCE_ID }, body: JSON.stringify({ email, password }), credentials: 'include' // IMPORTANT: Receive & Save cookies }); const authData = await handleAuthResponse(res); await this.getSession(); console.log("sign in", res); return await authData; } catch (err: any) { console.error("[Auth] signIn error:", err); return { error: err.message || 'Connection failed' }; } }, async signUp(email: string, password: string, name: string) { try { const url = `${AUTH_API_ROOT}/sign-up/email?Instance=${INSTANCE_ID}`; console.log(`[API] POST ${url}`, { email, name }); const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Database-Instance': INSTANCE_ID }, body: JSON.stringify({ email, password, name }), credentials: 'include' // IMPORTANT: Receive & Save cookies }); return await handleAuthResponse(res); } catch (err: any) { console.error("[Auth] signUp error:", err); return { error: err.message || 'Registration failed' }; } }, async signOut() { try { const url = `${AUTH_API_ROOT}/sign-out?Instance=${INSTANCE_ID}`; console.log(`[API] POST ${url}`); await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include' // IMPORTANT: Clear cookies }); } catch (err) { console.error("[Auth] signOut error:", err); } finally { localStorage.removeItem('ncb_session_token'); } } }; // --- DATA SERVICE --- export const dataService = { // -- PROFILES -- async getProfile(userId: string) { try { const encodedId = encodeURIComponent(userId); const url = `${DATA_API_ROOT}/read/profiles?Instance=${INSTANCE_ID}&user_id=${encodedId}`; console.log(`[API] GET ${url}`); const res = await fetch(url, { headers: getHeaders(), credentials: 'include' }); const json = await res.json(); console.log("[Data] getProfile result:", json); return json.data?.[0] || null; } catch (err) { console.error("[Data] getProfile error:", err); return null; } }, async createProfile(profileData: any) { return this.createItem('profiles', profileData); }, // -- PROJECTS -- async getProjects(userId: string) { try { const encodedId = encodeURIComponent(userId); const url = `${DATA_API_ROOT}/read/projects?Instance=${INSTANCE_ID}&user_id=${encodedId}`; console.log(`[API] GET ${url}`); const res = await fetch(url, { headers: getHeaders(), credentials: 'include' }); const json = await res.json(); console.log(`[Data] getProjects found ${json.data?.length || 0} items`); return json.data || []; } catch (err) { console.error("[Data] getProjects error:", err); return []; } }, async createProject(projectData: Partial & { user_id: string }) { // Map Frontend types to Database Columns explicitly if needed, but names match mostly // DB: title, author, genre, sub_genre, target_audience, tone, pov, tense, synopsis, themes, style_guide return this.createItem('projects', projectData); }, // -- GENERIC CRUD -- async getRelatedData(table: string, projectId: number) { try { const url = `${DATA_API_ROOT}/read/${table}?Instance=${INSTANCE_ID}&project_id=${projectId}`; console.log(`[API] GET ${url}`); const res = await fetch(url, { headers: getHeaders(), credentials: 'include' }); const json = await res.json(); console.log(`[Data] getRelatedData ${table} found ${json.data?.length || 0} items`); return json.data || []; } catch (err) { console.error(`[Data] getRelatedData ${table} error:`, err); return []; } }, async createItem(table: string, data: any) { try { console.log(`[Data] Creating item in ${table}...`, data); const url = `${DATA_API_ROOT}/create/${table}?Instance=${INSTANCE_ID}`; console.log(`[API] POST ${url}`, data); const res = await fetch(url, { method: 'POST', headers: getHeaders(), body: JSON.stringify(data), credentials: 'include' }); const result = await res.json(); console.log(`[Data] Create ${table} response:`, result); if (!res.ok) { console.error(`[Data] Create ${table} failed:`, result); return { status: 'error', message: result.message || 'Creation failed' }; } return { status: 'success', ...result }; } catch (err) { console.error(`[Data] Create ${table} network error:`, err); return { status: 'error', message: err }; } }, async updateItem(table: string, id: number, data: any) { try { const url = `${DATA_API_ROOT}/update/${table}/${id}?Instance=${INSTANCE_ID}`; console.log(`[API] PUT ${url}`, data); const res = await fetch(url, { method: 'PUT', headers: getHeaders(), body: JSON.stringify(data), credentials: 'include' }); if (!res.ok) { const err = await res.json(); console.error(`[Data] Update ${table} failed:`, err); } else { console.log(`[Data] Update ${table} success`); } } catch (err) { console.error(`[Data] Update ${table} error:`, err); } }, async deleteItem(table: string, id: number) { try { const url = `${DATA_API_ROOT}/delete/${table}/${id}?Instance=${INSTANCE_ID}`; console.log(`[API] DELETE ${url}`); const res = await fetch(url, { method: 'DELETE', headers: getHeaders(), credentials: 'include' }); if (!res.ok) { const err = await res.json(); console.error(`[Data] Delete ${table} failed:`, err); } else { console.log(`[Data] Delete ${table} success`); } } catch (err) { console.error(`[Data] Delete ${table} error:`, err); } } };