
const BASE_URL = process.env.EXPO_PUBLIC_API_URL+'/api';

export type NotificationType = 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION';
function authHeader(token?: string) {
    return token ? { Authorization: `Bearer ${token}` } : {};
}

let onUnauthorized: (() => void) | null = null;

// Called once from AuthProvider so api.tsx can trigger a logout/relogin
// when the backend rejects a request due to a missing/expired/invalid token.
export function setUnauthorizedHandler(handler: (() => void) | null) {
    onUnauthorized = handler;
}

async function request<T>(
    method: string,
    path: string,
    token?: string,
    body?: object,
    params?: Record<string, any>,
): Promise<T> {
    const url = new URL(`${BASE_URL}${path}`);
    if (params) {
        Object.entries(params).forEach(([k, v]) => {
            if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
        });
    }
    const res = await fetch(url.toString(), {
        method,
        // @ts-ignore
        headers: { "Content-Type": "application/json", ...authHeader(token) },
        ...(body ? { body: JSON.stringify(body) } : {}),
    });
    if (!res.ok) {
        const errorText = await res.text().catch(() => `HTTP ${res.status}`);
        console.log('Failed URL:', res.url);
        console.log('Status:', res.status);
        console.log('Response:', errorText);
        if (res.status === 401 && token) onUnauthorized?.();
        throw new Error(errorText);
    }
    return res.json();
}

export function get<T>(path: string, token?: string, params?: Record<string, any>) {
    return request<T>("GET", path, token, undefined, params);
}

export function post<T>(path: string, body: object, token?: string) {
    return request<T>("POST", path, token, body);
}

export function put<T>(
    path: string,
    body?: object,
    token?: string
) {
    return request<T>("PUT", path, token, body);
}

export function del<T>(path: string, token?: string) {
    return request<T>("DELETE", path, token);
}

export type Subject = {
    id: string;
    name: string;
};

export type JwtResponse = {
    token: string;
    email: string;
    userId: string;
    message: string;
};

export type UserDTO = {
    id: string;
    email: string;
    subjectSet: Subject[];
    notificationType: NotificationType;

};


export type UserUpdateDTO = {
    email: string;
    newEmail?: string;
    password?: string;
    subjectSet: { id: string }[]; // pass existing subscriptions so they aren't wiped
};



export type Entry = {
    id: string;
    title: string;
    timePublished: string;
    groupName: string;
    infoEntry: string;
    paragraph: string;
    filepath?: string;
    subject: Subject;
};

export type SpringPage<T> = {
    content: T[];
    totalPages: number;
    last: boolean;
    number: number;
};


export type LoginPayload = { email: string; password: string };
export type RegisterPayload = { email: string; password: string; name?: string };

export const authApi = {
    login: (p: LoginPayload) => post<JwtResponse>("/login", p),
    register: (p: RegisterPayload) => post<UserDTO>("/register", p),

    getUser: (token: string) =>
        get<UserDTO>("/users/me", token),

    updateUser: (body: UserUpdateDTO, token: string) =>
        request<UserDTO>("PUT", "/users/me", token, body),

    deleteUser: (token: string) =>
        del<void>("/users/me", token),
};


export const userApi = {
    updateNotificationType: (
        type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION',
        token: string
    ) => post<void>('/users/me/notification-type', { notificationType: type }, token),
};

export const subjectsApi = {
    getAll: (token?: string) => get<Subject[]>("/subjects", token),
};

export const subscriptionsApi = {
    subscribe: (subjectId: string, token: string) =>
        put<UserDTO>(
            `/users/me/subjects/${subjectId}`,
            {},
            token
        ),

    unsubscribe: (subjectId: string, token: string) =>
        del<UserDTO>(
            `/users/me/subjects/${subjectId}`,
            token
        ),
};



export const entriesApi = {
    getEntries: (params: { subjectId?: string; groupName?: string; page?: number }) =>
        get<SpringPage<Entry>>("/entries", undefined, params),
    getEntry: (id: string) => get<Entry>(`/entries/${id}`),
};
