import { addDays, subDays } from "date-fns";
import { Book, Chapter, Editor, Announcement, Glossary, Report } from "./types";

const API_URL = process.env.NEXT_PUBLIC_API_URL as string;
const API_TOKEN = process.env.STRAPI_API_TOKEN as string;

export async function createFromAPI<T>(
  endpoint: string,
  payload: string,
  options: RequestInit = {},
): Promise<T> {

  const headers: HeadersInit = {
    Authorization: `Bearer ${API_TOKEN}`,
    "Content-Type": "application/json",
  };


  const config: RequestInit = {
    method: "POST",
    headers,
    body: payload,
    ...options,
  }


  const response = await fetch(`${API_URL}${endpoint}`, config)
  if(!response.ok) {
    throw new Error(`API request failed with status ${response.status}`)
  }
  return response.json()
}

export async function fetchFromAPI<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T[]> {
  const headers: HeadersInit = {
    Authorization: `Bearer ${API_TOKEN}`,
    "Content-Type": "application/json",
  };


  const config: RequestInit = {
    method: "GET",
    headers,
    ...options,
  };



  let results: T[] = [];
  let currentPage = 1;
  let totalPages = 1;
  try {
    do {
      const url = `${API_URL}${endpoint}&pagination[page]=${currentPage}&pagination[pageSize]=25`;
      const response = await fetch(url, { ...config, next: { revalidate: 30 } });
      if (!response.ok) {
        const errorData = await response.json();
        console.error(`Error fetching ${url}:`, errorData);
        throw new Error(errorData.message || `API fetch error (status: ${response.status})`);
      }
      const responseJson = await response.json();
      results = results.concat(responseJson.data);
      totalPages = responseJson.meta?.pagination?.pageCount;
      currentPage += 1;
    } while (currentPage <= totalPages)

  } catch (error) {
    console.error("Fetch error:", error);
    throw error;
  }

  return results;
}

/**
 * Fetches all books from the API.
 * Populates optional fields like Chapters or Editors based on requirements.
 */
export async function fetchBooks(): Promise<Book[]> {
  const data = await fetchFromAPI<Book>("/api/books?populate=cover&sort[title]=asc");
  return data;
}

export async function fetchAnnouncements(): Promise<Announcement[]> {
  const data = await fetchFromAPI<Announcement>("/api/announcements?");
  return data;
}

export async function fetchChaptersRSS(): Promise<Chapter[]> {
  const currentDateTime = new Date()
  const yesterday = subDays(currentDateTime, 1);
  const data = await fetchFromAPI<Chapter>
    (`/api/chapters?populate=book&filters[release_datetime][$lte]=${currentDateTime.toISOString()}&filters[release_datetime][$gte]=${yesterday.toISOString()}`);
  return data;
}

export async function fetchBookChapterLinks(bookId: string): Promise<Book> {
  const currentDateTime = new Date().toISOString();
  const data = await fetchFromAPI<Book>(`/api/books/${bookId}?populate[chapters][filters][release_datetime][$lte]=${currentDateTime}`);
  return data[0]
}

/**
 * Fetches a specific book by ID with its chapters.
 * Filters chapters by release date to include only valid ones.
 */
export async function fetchBookById(bookId: string): Promise<Book> {
  const currentDateTime = new Date().toISOString();
  //[chapters][filters][release_datetime][$lte]=${currentDateTime}
  const data = await fetchFromAPI<Book>(
    `/api/books/${bookId}?populate[chapters][filters][release_datetime][$lte]=${currentDateTime}&populate=cover`
  );
  //I do not know why the hell it refuse to populate glossary only 1 field is allow to be populated after ????????
  const glossary = await fetchGlossaryByBookId(bookId);
  data[0].glossary = glossary;
  data[0].chapters = data[0].chapters.sort((a, b) => a.number - b.number);
  return data[0];
}

/**
 * Fetches a specific chapter by ID.
 */
export async function fetchChapterByBookId(bookId: string, chapterId: string): Promise<Chapter[]> {
  const currentChapter = await fetchFromAPI<Chapter>(`/api/chapters/${chapterId}?populate[book][fields][0]=title&filters[book][documentId]=${bookId}`);
  const bookWithAllChapters = await fetchFromAPI<Book>(`/api/books/${bookId}?populate[chapters][filters][number][$gte]=${currentChapter[0].number - 1
    }&populate[chapters][filters][number][$lte]=${currentChapter[0].number + 1
    }`);
  //const nextChapter = await fetchFromAPI<Chapter>(`/api/chapters?populate[book]&filters[book][id]=${bookId}&sort[number]=asc`);
  return bookWithAllChapters[0].chapters;
}

/**
 * Fetches all editors.
 */
export async function fetchEditors(): Promise<Editor[]> {
  const data = await fetchFromAPI<Editor>("/api/editors");
  return data;
}

export type ChapterRelease = { current_chapters: Chapter[], future_chapters: Chapter[] }
export async function fetchReleases(): Promise<{ current_chapters: Chapter[], future_chapters: Chapter[] }> {
  const current_datetime = new Date()
  const previous_week = subDays(current_datetime, 3);
  const next_week = addDays(current_datetime, 3);

  const data = await fetchFromAPI<Chapter>(`/api/chapters/?populate[book][fields][0]=title&fields[0]=number&fields[1]=title&fields[2]=release_datetime&filters[release_datetime][$gte]=${previous_week.toISOString()}&filters[release_datetime][$lte]=${next_week.toISOString()}`);
  const chapters: Chapter[] = data;
  const future_chapters = chapters.filter(chapter => new Date(chapter.release_datetime) > new Date());
  const current_chapters = chapters.filter(chapter => new Date(chapter.release_datetime) <= new Date());
  return { current_chapters, future_chapters }
}

export async function fetchAnnouncementById(announcementId: string): Promise<Announcement> {
  const data = await fetchFromAPI<Announcement>(`/api/announcements/${announcementId}?`);
  return data[0];
}

export async function fetchGlossaryByBookId(bookId: string): Promise<Glossary> {
  const data = await fetchFromAPI<Glossary>(`/api/glossaries?filters[book][documentId]=${bookId}`);
  return data[0];
}
export async function createReport(
  error_type: string, 
  details: string, 
  book_id: string, 
  chapter_id: string
): Promise<Report> {
  const payload = {
    data: {
      error_type,
      details,
      book: book_id,
      chapter: chapter_id
    }
  }
  const data = await createFromAPI<Report>(`/api/reports`, JSON.stringify(payload))
  return data
}