import { LoaderFunctionArgs, redirect, useLoaderData } from "react-router";
import {
  IPagination,
  createPagination,
  parsePageNumber,
} from "#lib/pagination";
import { createAccountsPageURL } from "#lib/urls";
import { apiCountAccounts, apiFetchAccounts } from "#api/account/administrator";
import { FormRouter } from "#components/forms";
import { Option } from "#components/forms/inputs";
import { FormSectionSelect, FormSectionText } from "#components/forms/sections";
import { Pagination, PaginationInfo } from "#components/pagination";
import { CardList } from "#components/cards";
import {
  PageSkeleton,
  validateAdministratorPageLoader,
} from "#components/pages";
import { Details } from "#components/details";
import {
  AccountPreview,
  IAccontRole,
  IAccount,
  accountRoles,
  ensureAccountRole,
} from "#entities/account";

import * as styles from "./accounts.module.scss";

interface IProps {
  name?: string;
  role?: IAccontRole;
  pagination: IPagination;
  accounts: IAccount[];
}

export function AdministratorAccountsPage() {
  const { name, role, pagination, accounts } = useLoaderData() as IProps;
  const title = "Accounts";
  const heading = "Accounts";

  return (
    <PageSkeleton name="admin-accounts" title={title} heading={heading}>
      <Details className={styles.filter} summary="Search">
        <FormRouter
          id="accounts-filter"
          method="GET"
          action="/account/administrator/accounts"
          submitButton={() => "Search"}
        >
          <FormSectionText
            id="search-name"
            name="name"
            label="Name"
            defaultValue={name}
          />

          <FormSectionSelect
            id="accounts-filter__roles"
            name="role"
            label="Roles"
            defaultValue={role}
            options={
              <>
                <Option value="">All</Option>
                {accountRoles.map((role) => (
                  <Option key={role} value={role}>
                    {role.toUpperCase()}
                  </Option>
                ))}
              </>
            }
          />
        </FormRouter>
      </Details>

      <PaginationInfo pagination={pagination} />

      <CardList layout="legacy">
        {accounts.length === 0 ? (
          <p>No accounts found.</p>
        ) : (
          accounts.map((account) => (
            <AccountPreview key={account.id} account={account} />
          ))
        )}
      </CardList>

      <Pagination
        action="/account/administrator/accounts"
        pagination={pagination}
        constructURL={(page) => String(createAccountsPageURL(page, name, role))}
        extraValues={{ name, role }}
      />
    </PageSkeleton>
  );
}

export async function loader(args: LoaderFunctionArgs): Promise<IProps> {
  await validateAdministratorPageLoader(args);

  const { request, params } = args;
  const searchParams = new URL(request.url).searchParams;

  const page = parsePageNumber(params.page?.trim());
  const name = searchParams.get("name")?.trim();

  let role: undefined | IAccontRole;
  {
    const inputValue = searchParams.get("role")?.trim();

    if (inputValue) {
      ensureAccountRole(inputValue);

      role = inputValue;
    }
  }

  const totalCount = await apiCountAccounts(name, role);

  if (totalCount === 0) {
    throw new Error("No accounts found.");
  }

  const pagination = createPagination(totalCount, page);
  const accounts = await apiFetchAccounts(pagination.current_page, name, role);

  return {
    accounts,
    pagination,
    name,
    role,
  };
}

export async function baseLoader(args: LoaderFunctionArgs) {
  await validateAdministratorPageLoader(args);

  const { request } = args;
  const searchParams = new URL(request.url).searchParams;

  const name = searchParams.get("name")?.trim();

  let page: number | undefined = undefined;
  {
    const inputValue = searchParams.get("page")?.trim();
    if (inputValue) {
      page = parsePageNumber(inputValue);
    }
  }

  let role: undefined | IAccontRole;
  {
    const inputValue = searchParams.get("role")?.trim();

    if (inputValue) {
      ensureAccountRole(inputValue);

      role = inputValue;
    }
  }

  const totalCount = await apiCountAccounts(name, role);

  if (totalCount === 0) {
    throw new Error("No accounts found.");
  }

  const pagination = createPagination(totalCount, page);
  const url = String(
    createAccountsPageURL(pagination.current_page, name, role)
  );

  return redirect(url);
}
