import {
  ActionFunctionArgs,
  LoaderFunctionArgs,
  redirect,
  useLoaderData,
} from "react-router-dom";
import clsx from "clsx";
import { IPagination } from "#lib/pagination";
import { createAccountsPageURL } from "#lib/urls";
import {
  fetchAccounts,
  fetchChangeRolesOfAccounts,
} from "#api/account/administrator";
import { FormRouter } from "#components/forms";
import { Pagination, PaginationController } from "#components/pagination";
import { CardList, AccountCard } from "#components/cards";
import { PageSkeleton, createAccountPageLoader } from "#components/pages";
import { IAccontRole, IAccount, accountRoles } from "#entities/account";

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

type IRole = "all" | IAccontRole;

const roleValues = ["all", ...accountRoles] as const satisfies IRole[];

function isRoleValue(input: unknown): input is IRole {
  return roleValues.includes(input as IRole);
}

export function AdministratorAccountsPage() {
  const { name, role, roleList, pagination, limit, accounts } =
    useLoaderData() as IProps;
  const title = "Accounts";
  const heading = "Accounts";
  const formID = "account-pages";

  return (
    <PageSkeleton name="admin-accounts" title={title} heading={heading}>
      <FormRouter id="accounts-filter" method="GET">
        <div className="form__section">
          <label className="form__label" htmlFor="search-name">
            Name:
          </label>
          <input
            id="search-name"
            className="form__input"
            type="text"
            name="name"
            defaultValue={name}
          />
        </div>
        <div className="form__section">
          <label className="form__label" htmlFor="accounts-filter__roles">
            Roles:
          </label>
          <select
            id="accounts-filter__roles"
            className="form__select"
            name="role"
            defaultValue={role}
          >
            <option className="form__option" value="all">
              All
            </option>
            {roleList.map((role) => (
              <option className="form__option" value={role}>
                {role.toUpperCase()}
              </option>
            ))}
          </select>
        </div>
        <div className="form__section">
          <button className="form__button form__button--submit" type="submit">
            Search
          </button>
        </div>
      </FormRouter>

      <FormRouter id="account-list" method="POST">
        <Pagination
          controllerID={formID}
          pagination={pagination}
          constructURL={(page) =>
            String(createAccountsPageURL(page, name, role, limit))
          }
        />

        <CardList layout="legacy">
          {accounts.length === 0 ? (
            <p>No accounts found.</p>
          ) : (
            accounts.map((account) =>
              account.role === "moderator" ? (
                <div
                  key={account.id}
                  className={clsx(
                    "form__section",
                    "account__view",
                    "account__view--demote"
                  )}
                >
                  <input
                    id={`account-${account.id}`}
                    className="form__input account__role-check"
                    type="checkbox"
                    name="consumer"
                    defaultValue={account.id}
                  />

                  <div className="account__info">
                    <AccountCard account={account} />
                    <label
                      className="form__label account__label"
                      htmlFor={`account-${account.id}`}
                    >
                      Demote
                    </label>
                  </div>
                </div>
              ) : account.role === "consumer" ? (
                <div
                  key={account.id}
                  className={clsx(
                    "form__section",
                    "account__view",
                    "account__view--promote"
                  )}
                >
                  <input
                    id={`account-${account.id}`}
                    className="form__input account__role-check"
                    type="checkbox"
                    name="moderator"
                    defaultValue={account.id}
                  />
                  <div className="account__info">
                    <AccountCard account={account} />
                    <label
                      className="form__label account__label"
                      htmlFor={`account-${account.id}`}
                    >
                      Promote
                    </label>
                  </div>
                </div>
              ) : undefined
            )
          )}
        </CardList>

        {accounts.length !== 0 && (
          <div className={clsx("form__section", "form__section--buttons")}>
            <button className="form__button form__button--submit" type="submit">
              Submit
            </button>
          </div>
        )}
      </FormRouter>

      <PaginationController
        id={formID}
        params={{ name, role, limit: String(limit) }}
      />
    </PageSkeleton>
  );
}

export const loader = createAccountPageLoader(async function loader({
  request,
}: LoaderFunctionArgs): Promise<IProps> {
  const searchParams = new URL(request.url).searchParams;

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

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

  let role: undefined | IRole;
  {
    const inputValue = searchParams.get("role")?.trim();
    if (inputValue) {
      if (!isRoleValue(inputValue)) {
        throw new Error(`Invalid role value "${inputValue}".`);
      }

      role = inputValue;
    }
  }

  let limit: undefined | number = undefined;
  {
    const inputValue = searchParams.get("limit")?.trim();
    if (inputValue) {
      limit = Number.parseInt(inputValue, 10);
    }
  }

  const { accounts, pagination, role_list } = await fetchAccounts(
    page,
    name,
    role,
    limit
  );

  return {
    accounts,
    pagination,
    roleList: role_list,
    name,
    role,
    limit,
  };
});

export async function action({ request }: ActionFunctionArgs) {
  try {
    if (request.method !== "POST") {
      throw new Error(`Unknown method "${request.method}".`);
    }

    const data = await request.formData();
    const moderators = data.getAll("moderator") as string[];
    const consumers = data.getAll("consumer") as string[];

    await fetchChangeRolesOfAccounts(moderators, consumers);

    return redirect(String(createAccountsPageURL()));
  } catch (error) {
    return error;
  }
}
