import type { RequestHandler } from '@sveltejs/kit';
import {
  addGuestbookComment,
  deleteGuestbookComment,
  getGuestbookComments,
  type GuestbookAuthor
} from '$lib/server/guestbookStore';
import { getSession } from '$lib/server/sessionStore';

const MAX_COMMENT_LENGTH = 2000;
const PLAYER_ENDPOINT = 'https://api.beatleader.com/player/';
const DEFAULT_PAGE_SIZE = 5;
const MAX_PAGE_SIZE = 50;

type GuestbookViewer = {
  beatleaderId: string;
  name: string | null;
  avatar: string | null;
};

type GuestbookResponse = {
  viewer: GuestbookViewer | null;
  comments: ReturnType<typeof getGuestbookComments>;
  pagination: {
    total: number;
    offset: number;
    limit: number;
    hasPrev: boolean;
    hasNext: boolean;
  };
};

function mapSessionToViewer(session: ReturnType<typeof getSession>): GuestbookViewer | null {
  if (!session) return null;
  return {
    beatleaderId: session.beatleaderId,
    name: session.name ?? null,
    avatar: session.avatar ?? null
  };
}

async function buildAuthor(session: NonNullable<ReturnType<typeof getSession>>, fetchFn: typeof fetch): Promise<GuestbookAuthor> {
  const base: GuestbookAuthor = {
    beatleaderId: session.beatleaderId,
    name: session.name ?? null,
    avatar: session.avatar ?? null,
    country: null,
    rank: null,
    techPp: null,
    accPp: null,
    passPp: null
  };

  try {
    const res = await fetchFn(`${PLAYER_ENDPOINT}${encodeURIComponent(session.beatleaderId)}?stats=true`);
    if (!res.ok) return base;
    const data = (await res.json()) as Record<string, unknown>;
    return {
      beatleaderId: session.beatleaderId,
      name: typeof data.name === 'string' ? (data.name as string) : base.name,
      avatar: typeof data.avatar === 'string' ? (data.avatar as string) : base.avatar,
      country: typeof data.country === 'string' ? (data.country as string) : base.country,
      rank: typeof data.rank === 'number' ? (data.rank as number) : base.rank,
      techPp: typeof data.techPp === 'number' ? (data.techPp as number) : base.techPp,
      accPp: typeof data.accPp === 'number' ? (data.accPp as number) : base.accPp,
      passPp: typeof data.passPp === 'number' ? (data.passPp as number) : base.passPp
    };
  } catch (error) {
    console.error('Failed to load BeatLeader profile for guestbook author', error);
    return base;
  }
}

function sanitizeMessage(value: unknown): { ok: true; message: string } | { ok: false; error: string } {
  if (typeof value !== 'string') {
    return { ok: false, error: 'Message must be a string' };
  }
  const trimmed = value.trim();
  if (!trimmed) {
    return { ok: false, error: 'Message cannot be empty' };
  }
  if (trimmed.length > MAX_COMMENT_LENGTH) {
    return { ok: false, error: `Message exceeds ${MAX_COMMENT_LENGTH} characters` };
  }
  return { ok: true, message: trimmed };
}

function parseLimit(value: string | null): number {
  if (!value) return DEFAULT_PAGE_SIZE;
  const parsed = Math.floor(Number(value));
  if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_PAGE_SIZE;
  return Math.min(MAX_PAGE_SIZE, parsed);
}

function parseOffset(value: string | null): number {
  if (!value) return 0;
  const parsed = Math.floor(Number(value));
  if (!Number.isFinite(parsed) || parsed <= 0) return 0;
  return parsed;
}

function clampOffset(offset: number, total: number): number {
  if (total <= 0) return 0;
  const safeOffset = Math.max(0, Math.floor(offset));
  const maxOffset = Math.max(0, total - 1);
  return Math.min(safeOffset, maxOffset);
}

function buildGuestbookPayload(
  session: ReturnType<typeof getSession>,
  limit: number,
  offset: number
): GuestbookResponse {
  const allComments = getGuestbookComments();
  const total = allComments.length;
  const safeLimit = Math.max(1, Math.min(MAX_PAGE_SIZE, Math.floor(limit)));
  const safeOffset = clampOffset(offset, total);
  const pageComments = allComments.slice(safeOffset, safeOffset + safeLimit);

  return {
    viewer: mapSessionToViewer(session),
    comments: pageComments,
    pagination: {
      total,
      offset: safeOffset,
      limit: safeLimit,
      hasPrev: safeOffset > 0,
      hasNext: safeOffset + safeLimit < total
    }
  };
}

function jsonResponse(payload: GuestbookResponse, init?: ResponseInit): Response {
  return new Response(JSON.stringify(payload), {
    headers: { 'content-type': 'application/json' },
    ...init
  });
}

export const GET: RequestHandler = ({ cookies, url }) => {
  const session = getSession(cookies);
  const limit = parseLimit(url.searchParams.get('limit'));
  const offset = parseOffset(url.searchParams.get('offset'));

  return jsonResponse(buildGuestbookPayload(session, limit, offset));
};

export const POST: RequestHandler = async ({ request, cookies, fetch }) => {
  const session = getSession(cookies);
  if (!session) {
    return new Response(
      JSON.stringify({ error: 'Unauthorized', login: '/auth/beatleader/login' }),
      { status: 401, headers: { 'content-type': 'application/json' } }
    );
  }

  let body: unknown;
  try {
    body = await request.json();
  } catch {
    return new Response(JSON.stringify({ error: 'Invalid JSON body' }), {
      status: 400,
      headers: { 'content-type': 'application/json' }
    });
  }

  const sanitizedMessage = sanitizeMessage((body as Record<string, unknown>)?.message);
  if (!sanitizedMessage.ok) {
    return new Response(JSON.stringify({ error: sanitizedMessage.error }), {
      status: 400,
      headers: { 'content-type': 'application/json' }
    });
  }

  const { message } = sanitizedMessage;

  try {
    const author = await buildAuthor(session, fetch);
    addGuestbookComment({ message, author });
  } catch (error) {
    const msg = error instanceof Error ? error.message : 'Failed to save comment';
    return new Response(JSON.stringify({ error: msg }), {
      status: 400,
      headers: { 'content-type': 'application/json' }
    });
  }

  return jsonResponse(buildGuestbookPayload(session, DEFAULT_PAGE_SIZE, 0), { status: 201 });
};

export const DELETE: RequestHandler = ({ url, cookies }) => {
  const session = getSession(cookies);
  if (!session) {
    return new Response(
      JSON.stringify({ error: 'Unauthorized', login: '/auth/beatleader/login' }),
      { status: 401, headers: { 'content-type': 'application/json' } }
    );
  }

  const id = url.searchParams.get('id') || null;
  if (!id) {
    return new Response(JSON.stringify({ error: 'Missing comment id' }), {
      status: 400,
      headers: { 'content-type': 'application/json' }
    });
  }

  const success = deleteGuestbookComment(id, session.beatleaderId);
  if (!success) {
    return new Response(JSON.stringify({ error: 'Comment not found or not owned by you' }), {
      status: 404,
      headers: { 'content-type': 'application/json' }
    });
  }

  const limit = parseLimit(url.searchParams.get('limit'));
  const offset = parseOffset(url.searchParams.get('offset'));
  return jsonResponse(buildGuestbookPayload(session, limit, offset), { status: 200 });
};


