import { assembleQueryParams, FetchError } from '../utils/FetchHelper';
import { APIColumnDef } from '../utils/TableHelper';
import { getFormattedTeamName, getTeams } from './Teams';

// Define API endpoint for notifications
export const NOTIFICATIONS_API_URL =
  location.protocol + location.host + '/api/notifications';
export const READ_NOTIFICATIONS_API_URL =
  location.protocol + location.host + '/api/read_notifications';

// Define TypeScript types for notifications
export type Notification = {
  notification_id?: number;
  notification_timestamp?: string;
  request_id?: number;
  team_id: number;
  generated_message: string;
  free_text?: string;
  for_instructor: boolean;
};
export type NotificationPatch = {};
export type NotificationTableData = {
  notification_id?: number | string;
  notification_timestamp?: string;
  request_id?: number | string;
  team_id: number | string;
  generated_message: string;
  free_text?: string;
  for_instructor: boolean | string;
};
export type ReadNotification = {
  read_notification_id?: number;
  notification_id: number;
  user_id: number;
};

// Function transforms an array of Notification objects and replaces members with new formatted strings for table display
// IN: notifications : Notification array to be transformed
// OUT: transformed NotificationTableData array
export async function transformNotifications(
  notifications: Notification[]
): Promise<NotificationTableData[]> {
  // Get data for foreign key objects
  const teams = await getTeams();

  notifications.forEach((notification: NotificationTableData) => {
    const team = teams.find((team) => team.team_id === notification.team_id);

    if (team) {
      notification.team_id = getFormattedTeamName(team, undefined, true);
    }
  });

  return notifications;
}

// Define ColumnDef array for Notification type
export const defaultNotificationColumns: APIColumnDef<
  NotificationTableData,
  NotificationPatch
>[] = [
  {
    accessorKey: 'notification_id',
    header: 'ID',
    enableColumnFilter: false,
  },
  {
    accessorKey: 'notification_timestamp',
    header: 'Timestamp',
    sortDescFirst: false,
    enableColumnFilter: false,
    meta: {
      transform: (value) => new Date(value).toLocaleString(),
    },
  },
  {
    accessorKey: 'request_id',
    header: 'Request ID',
    sortDescFirst: false,
    enableColumnFilter: false,
  },
  {
    accessorKey: 'team_id',
    header: 'Team',
    sortDescFirst: false,
    filterFn: 'equalsString',
  },
  {
    accessorKey: 'generated_message',
    header: 'Generated Message',
    enableSorting: false,
    enableColumnFilter: false,
  },
  {
    accessorKey: 'free_text',
    header: 'Instructor Comment',
    enableSorting: false,
    enableColumnFilter: false,
  },
  {
    accessorKey: 'for_instructor',
    header: 'Instructor Notification',
    filterFn: 'equalsString',
    meta: {
      transform: (value) => value.toString(),
    },
  },
];

// Function makes GET request to retrieve notifications
export async function getNotifications(
  team_id?: number,
  for_instructor?: boolean
): Promise<Notification[]> {
  const _url = assembleQueryParams(NOTIFICATIONS_API_URL, {
    team_id: team_id?.toString(),
    for_instructor: for_instructor?.toString(),
  });

  try {
    const response = await fetch(_url.toString());
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to retrieve notifications',
        response
      );
    }
    return await response.json();
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

// Function makes POST request to create a notification
export async function createNotification(
  notification: Notification
): Promise<Notification> {
  const _url = new URL(NOTIFICATIONS_API_URL);

  try {
    const response = await fetch(_url.toString(), {
      headers: {
        'Content-Type': 'application/json',
      },
      method: 'POST',
      body: JSON.stringify(notification),
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to create notification',
        response
      );
    }
    return await response.json();
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

// Function makes DELETE request to remove a notification
export async function deleteNotification(
  notification_id: number
): Promise<Response> {
  const _url = new URL(NOTIFICATIONS_API_URL + '/' + notification_id);

  try {
    const response = await fetch(_url.toString(), {
      method: 'DELETE',
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to delete notification',
        response
      );
    }
    return response;
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

// Function makes a GET request to retrieve read notifications
export async function getReadNotifications(
  user_id?: number
): Promise<ReadNotification[]> {
  const _url = assembleQueryParams(READ_NOTIFICATIONS_API_URL, {
    user_id: user_id?.toString(),
  });

  try {
    const response = await fetch(_url.toString());
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to retrieve read notifications',
        response
      );
    }
    return await response.json();
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

// Function makes a POST request to create a read notification
export async function createReadNotification(
  read_notifcation: ReadNotification
): Promise<ReadNotification> {
  const _url = new URL(READ_NOTIFICATIONS_API_URL);

  try {
    const response = await fetch(_url.toString(), {
      headers: {
        'Content-Type': 'application/json',
      },
      method: 'POST',
      body: JSON.stringify(read_notifcation),
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to create read notification',
        response
      );
    }
    return await response.json();
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

// Function makes a DELETE request to delete a read notification
export async function deleteReadNotification(
  read_notification_id: number
): Promise<Response> {
  const _url = new URL(READ_NOTIFICATIONS_API_URL + '/' + read_notification_id);

  try {
    const response = await fetch(_url.toString(), {
      method: 'DELETE',
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to delete read notification',
        response
      );
    }
    return response;
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}
