import { useCallback, useEffect, useMemo, useState } from 'react';
import { useQuery, UseQueryExecute } from 'urql';
import { OrganizationLayout, Page } from '@/components/layouts/organization';
import { SubPageNavigationLink } from '@/components/navigation/sub-page-navigation-link';
import { OrganizationInvitations } from '@/components/organization/members/invitations';
import { OrganizationMembers } from '@/components/organization/members/list';
import { OrganizationMemberRoles } from '@/components/organization/members/roles';
import { Meta } from '@/components/ui/meta';
import { NavLayout, PageLayout, PageLayoutContent } from '@/components/ui/page-content-layout';
import { QueryError } from '@/components/ui/query-error';
import { FragmentType, graphql, useFragment } from '@/gql';
import { useRedirect } from '@/lib/access/common';
import { organizationMembersRoute } from '../router';

const OrganizationMembersPage_OrganizationFragment = graphql(`
  fragment OrganizationMembersPage_OrganizationFragment on Organization {
    ...OrganizationInvitations_OrganizationFragment
    ...OrganizationMemberRoles_OrganizationFragment
    ...OrganizationMembers_OrganizationFragment

    viewerCanManageInvitations
    viewerCanManageRoles
  }
`);

const subPages = [
  {
    key: 'list',
    title: 'Members',
  },
  {
    key: 'roles',
    title: 'Roles',
  },
  {
    key: 'invitations',
    title: 'Invitations',
  },
] as const;

type SubPage = (typeof subPages)[number]['key'];

function PageContent(props: {
  page: SubPage;
  onPageChange(page: SubPage): void;
  organization: FragmentType<typeof OrganizationMembersPage_OrganizationFragment>;
  refetchQuery: UseQueryExecute;
  setAfter: (after: string | null) => void;
}) {
  const organization = useFragment(
    OrganizationMembersPage_OrganizationFragment,
    props.organization,
  );

  const filteredSubPages = useMemo(() => {
    return subPages.filter(page => {
      if (!organization.viewerCanManageInvitations && page.key === 'invitations') {
        return false;
      }
      if (!organization.viewerCanManageRoles && page.key === 'roles') {
        return false;
      }
      return true;
    });
  }, [organization.viewerCanManageInvitations, organization.viewerCanManageRoles]);

  if (!organization) {
    return null;
  }

  return (
    <PageLayout>
      <NavLayout>
        {filteredSubPages.map(subPage => (
          <SubPageNavigationLink
            key={subPage.key}
            isActive={props.page === subPage.key}
            onClick={() => props.onPageChange(subPage.key)}
            title={subPage.title}
          />
        ))}
      </NavLayout>
      <PageLayoutContent>
        {props.page === 'list' ? (
          <OrganizationMembers
            refetchMembers={props.refetchQuery}
            organization={organization}
            setAfter={props.setAfter}
          />
        ) : null}
        {props.page === 'roles' && organization.viewerCanManageRoles ? (
          <OrganizationMemberRoles organization={organization} />
        ) : null}
        {props.page === 'invitations' && organization.viewerCanManageInvitations ? (
          <OrganizationInvitations
            refetchInvitations={props.refetchQuery}
            organization={organization}
          />
        ) : null}
      </PageLayoutContent>
    </PageLayout>
  );
}

const OrganizationMembersPageQuery = graphql(`
  query OrganizationMembersPageQuery(
    $organizationSlug: String!
    $searchTerm: String
    $first: Int
    $after: String
  ) {
    organization: organizationBySlug(organizationSlug: $organizationSlug) {
      ...OrganizationMembersPage_OrganizationFragment
      viewerCanSeeMembers
    }
  }
`);

function OrganizationMembersPageContent(props: {
  organizationSlug: string;
  page: SubPage;
  onPageChange(page: SubPage): void;
}) {
  const search = organizationMembersRoute.useSearch();
  const [after, setAfter] = useState<string | null>(null);

  // Reset cursor when search changes
  useEffect(() => {
    setAfter(null);
  }, [search.search]);

  const [query, refetch] = useQuery({
    query: OrganizationMembersPageQuery,
    variables: {
      organizationSlug: props.organizationSlug,
      searchTerm: search.search || undefined,
      first: 20,
      after,
    },
  });

  useRedirect({
    canAccess: query.data?.organization?.viewerCanSeeMembers === true,
    redirectTo: router => {
      void router.navigate({
        to: '/$organizationSlug',
        params: {
          organizationSlug: props.organizationSlug,
        },
      });
    },
    entity: query.data?.organization,
  });

  const refetchQuery = useCallback(() => {
    refetch({ requestPolicy: 'network-only' });
  }, [refetch]);

  if (query.data?.organization?.viewerCanSeeMembers === false) {
    return null;
  }

  if (query.error) {
    return <QueryError organizationSlug={props.organizationSlug} error={query.error} />;
  }

  return (
    <OrganizationLayout
      organizationSlug={props.organizationSlug}
      page={Page.Members}
      className="flex flex-col gap-y-10"
    >
      {query.data?.organization ? (
        <PageContent
          organization={query.data.organization}
          onPageChange={props.onPageChange}
          page={props.page}
          refetchQuery={refetchQuery}
          setAfter={setAfter}
        />
      ) : null}
    </OrganizationLayout>
  );
}

export function OrganizationMembersPage(props: {
  organizationSlug: string;
  page: SubPage;
  onPageChange(page: SubPage): void;
}) {
  return (
    <>
      <Meta title="Members" />
      <OrganizationMembersPageContent
        organizationSlug={props.organizationSlug}
        page={props.page}
        onPageChange={props.onPageChange}
      />
    </>
  );
}
