import { SxProps } from "@mui/system";

import { OpenAPI } from "openapi-types";

import { RouteInfo } from "../contexts/RouterContext";

export * from "./dashboard";
export type * from "./mui-chips-input";
export type * from "./mui-material-styles";

export type LogoType = boolean | string | React.ElementType;

/**
 * A `Page` loaded by the `PageLoader`.
 * Use `refresh` to reload data.
 * @param T The data corresponding to the django operation.
 *
 * TODO: Return way to set data from an external source, such as the `POST` of the operation.
 */
export interface PageProps<T = unknown> {
  data: T;
  refresh: () => void;
}

export type PageComponent<T = unknown> = React.ComponentType<PageProps<T>> & {
  requiredQuery?: URLSearchParams;
  defaultQuery?: URLSearchParams;
};

export interface NavigationItem {
  /**
   * The title shown in the NavRail. Takes precedence over the title in the component.
   */
  title?: string;
  /**
   * The logo shown in the NavRail. Takes precedence over the title in the component.
   */
  icon?: LogoType;
  /**
   * Route information for the navigation item. Picked up by the `RouterContext`.
   */
  route?: RouteInfo;
  /**
   * Django user permission string, currently only supports a single permission.
   * Will return `null` if the user does not have the permission.
   */
  permission?: string;
  /**
   * Django user group string, currently only supports a single group.
   * Will return `null` if the user is not in the group.
   */
  group?: string;
  /**
   * Django user group string, currently only supports a single group.
   * Will hide the navigation item if the user is in the group.
   */
  excludedGroup?: string;
  /**
   * Whether the navigation item should be hidden from NavRail.
   */
  hidden?: boolean;
}

/**
 * A map of navigation overrides for the application.
 * @note Keys that are valid URLs (per `isURL`) will be treated as external links and turned into `a` tags.
 */
export type NavigationOverrides = Record<string, NavigationItem | null | undefined | false>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ContribComponent<T = any> = React.ComponentType<
  PageProps<T> & OpenAPI.Request & { sx?: SxProps; close?: () => void }
>;

/**
 * The variant of the component, either a tab, inline or action menu item.
 * Still requires a `Page` that loads the contrib.
 */
export type ContribVariant = "tab" | "inline" | "action";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface PageContribComponent<T = any> extends OpenAPI.Request {
  /**
   * The title shown in the NavRail.
   */
  title?: string;
  /**
   * The icon shown in the NavRail.
   */
  icon?: LogoType;
  /**
   * The component to render, expected to be a Page, not a single `Card` or `Table`.
   */
  component?: ContribComponent<T> | Promise<ContribComponent<T>>;
  /**
   * The variant of the component, either a tab or inline.
   */
  variant: ContribVariant;
  /**
   * An optional predicate to determine if the component should be shown.
   * @param obj The data object to check against.
   */
  predicate?: (obj?: T) => boolean;
  /**
   * Django user permission string, currently only supports a single permission.
   * Will return `null` if the user does not have the permission.
   */
  permission?: string;
  /**
   * Django user group string, currently only supports a single group.
   * Will return `null` if the user is not in the group.
   */
  group?: string;
}

export type ContribComponentMap = Record<
  string,
  Omit<PageContribComponent, "component"> & {
    component?: () => PageContribComponent["component"];
  }
>;

export type ContribComponentListItem = {
  tag: string;
  contrib: ContribComponentMap[string];
};

export type ContribComponentList = ContribComponentListItem[];

/**
 * A paginated Django list.
 */
export interface LimitOffset<T> {
  next?: string;
  previous?: string;
  results: T[];
  count: number;
}
