import { error, redirect, fail } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import { zod4 } from 'sveltekit-superforms/adapters';

import { Roles } from '$lib/types/user';
import { workBookSchema } from '$features/workbooks/zod/schema';

import * as tasksCrud from '$lib/services/tasks';
import { getLoggedInUser } from '$features/auth/services/session_guards';
import * as workBooksCrud from '$features/workbooks/services/workbooks';

import { canEdit, isAdmin } from '$lib/utils/authorship';
import { parseWorkBookId, parseWorkBookUrlSlug } from '$features/workbooks/utils/workbook';

import {
  BAD_REQUEST,
  FORBIDDEN,
  NOT_FOUND,
  TEMPORARY_REDIRECT,
  INTERNAL_SERVER_ERROR,
} from '$lib/constants/http-response-status-codes';

export async function load({ locals, params, url }) {
  const loggedInUser = await getLoggedInUser(locals, url);
  const loggedInAsAdmin = isAdmin(loggedInUser?.role as Roles);
  const slug = params.slug.toLowerCase();

  if (!parseWorkBookId(slug) && !parseWorkBookUrlSlug(slug)) {
    error(BAD_REQUEST, '不正な問題集idです。');
  }

  const workBookWithAuthor = await workBooksCrud.getWorkbookWithAuthor(slug);

  if (!workBookWithAuthor) {
    error(NOT_FOUND, `問題集id: ${slug} は見つかりませんでした。`);
  }

  const form = await superValidate(null, zod4(workBookSchema));
  const workBook = {
    ...workBookWithAuthor.workBook,
    urlSlug: workBookWithAuthor.workBook.urlSlug ?? undefined,
  };
  form.data = { ...form.data, ...workBook };
  const tasks = await tasksCrud.getTasks();
  const tasksMapByIds = await tasksCrud.getTasksByTaskId();

  // ユーザidと問題集の作成者idが一致しない場合、ページへのアクセス権限がないことを表示する
  // 例外として、管理者はユーザの問題集を編集できる
  // HACK: load関数内でfailを使うと、プレーンオブジェクトを返していないというエラーが解決できず
  // やむを得ず、return文で直接オブジェクトを返しているが、もっとシンプルに記述できるはず
  if (
    loggedInUser &&
    !canEdit(
      loggedInUser.id,
      workBookWithAuthor.workBook.authorId,
      loggedInUser.role as Roles,
      workBookWithAuthor.workBook.isPublished,
    )
  ) {
    return {
      status: FORBIDDEN,
      message: `問題集id: ${slug}にアクセスする権限がありません。`,
      form,
      loggedInAsAdmin: loggedInAsAdmin,
      ...workBookWithAuthor,
      tasks,
      tasksMapByIds,
    };
  }

  return {
    form: form,
    loggedInAsAdmin: loggedInAsAdmin,
    ...workBookWithAuthor,
    tasks: tasks,
    tasksMapByIds: tasksMapByIds,
  };
}

export const actions = {
  default: async ({ request, params, locals, url }) => {
    const loggedInUser = await getLoggedInUser(locals, url);
    const slug = params.slug.toLowerCase();
    const workBookWithAuthor = await workBooksCrud.getWorkbookWithAuthor(slug);

    if (!workBookWithAuthor) {
      error(NOT_FOUND, `問題集id: ${slug} は見つかりませんでした。`);
    }

    if (
      !canEdit(
        loggedInUser.id,
        workBookWithAuthor.workBook.authorId,
        loggedInUser.role as Roles,
        workBookWithAuthor.workBook.isPublished,
      )
    ) {
      error(FORBIDDEN, `問題集id: ${slug}にアクセスする権限がありません。`);
    }

    const form = await superValidate(request, zod4(workBookSchema));

    if (!form.valid) {
      return {
        form: {
          ...form,
          message:
            '問題集の入力項目に不正な値があります。修正してから、「更新」ボタンを押してください。',
        },
      };
    }

    const workBook = form.data;
    const workBookId = workBookWithAuthor.workBook.id;

    try {
      await workBooksCrud.updateWorkBook(workBookId, { ...workBook, id: workBookId });
      console.log(`Updated workbook ${workBookId}`);
    } catch (e) {
      console.error(`Failed to update WorkBook with id ${workBookId}:`, e);

      return fail(INTERNAL_SERVER_ERROR, {
        form: {
          ...form,
          message: `問題集: ${workBookId} の更新に失敗しました。しばらくしてから、もう一度試してください。`,
        },
      });
    }

    redirect(TEMPORARY_REDIRECT, '/workbooks');
  },
};
