import { ReactNode, useEffect, useState } from 'react';
import { HardDrive, RefreshCcw } from 'lucide-react';
import _ from 'lodash';
import { useStore } from 'zustand';

import { usePaginationLimitState } from '@/react/hooks/usePaginationLimitState';
import {
  Environment,
  EnvironmentType,
  EnvironmentStatus,
  PlatformType,
  EdgeTypes,
} from '@/react/portainer/environments/types';
import { EnvironmentGroupId } from '@/react/portainer/environments/environment-groups/types';
import {
  refetchIfAnyOffline,
  useEnvironmentList,
} from '@/react/portainer/environments/queries/useEnvironmentList';
import { useGroups } from '@/react/portainer/environments/environment-groups/queries';
import { EnvironmentsQueryParams } from '@/react/portainer/environments/environment.service';
import { useUser } from '@/react/hooks/useUser';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { environmentStore } from '@/react/hooks/current-environment-store';

import { TableFooter } from '@@/datatables/TableFooter';
import { TableContainer, TableTitle } from '@@/datatables';
import { Button } from '@@/buttons';
import { PaginationControls } from '@@/PaginationControls';
import { SearchBar, useSearchBarState } from '@@/datatables/SearchBar';

import { useHomePageFilter } from './HomepageFilter';
import { ConnectionType, Filter } from './types';
import { EnvironmentItem } from './EnvironmentItem';
import { KubeconfigButton } from './KubeconfigButton';
import { NoEnvironmentsInfoPanel } from './NoEnvironmentsInfoPanel';
import { UpdateBadge } from './UpdateBadge';
import { EnvironmentListFilters } from './EnvironmentListFilters';
import { AMTButton } from './AMTButton/AMTButton';

interface Props {
  onClickBrowse(environment: Environment): void;
  onRefresh(): void;
}

const storageKey = 'home_endpoints';

export function EnvironmentList({ onClickBrowse, onRefresh }: Props) {
  const { isAdmin } = useUser();
  const currentEnvStore = useStore(environmentStore);

  const [platformTypes, setPlatformTypes] = useHomePageFilter<
    Filter<PlatformType>[]
  >('platformType', []);
  const [searchBarValue, setSearchBarValue] = useSearchBarState(storageKey);
  const [pageLimit, setPageLimit] = usePaginationLimitState(storageKey);
  const [page, setPage] = useState(1);

  const [connectionTypes, setConnectionTypes] = useHomePageFilter<
    Filter<ConnectionType>[]
  >('connectionTypes', []);

  const [statusFilter, setStatusFilter] = useHomePageFilter<
    EnvironmentStatus[]
  >('status', []);
  const [tagFilter, setTagFilter] = useHomePageFilter<number[]>('tag', []);
  const [groupFilter, setGroupFilter] = useHomePageFilter<EnvironmentGroupId[]>(
    'group',
    []
  );
  const [sortByFilter, setSortByFilter] = useSearchBarState('sortBy');
  const [sortByDescending, setSortByDescending] = useHomePageFilter(
    'sortOrder',
    false
  );
  const [sortByButton, setSortByButton] = useHomePageFilter(
    'sortByButton',
    false
  );

  const [statusState, setStatusState] = useHomePageFilter<Filter[]>(
    'status_state',
    []
  );
  const [tagState, setTagState] = useHomePageFilter<Filter[]>('tag_state', []);
  const [groupState, setGroupState] = useHomePageFilter<Filter[]>(
    'group_state',
    []
  );
  const [sortByState, setSortByState] = useHomePageFilter<Filter | undefined>(
    'sort_by_state',
    undefined
  );
  const [agentVersions, setAgentVersions] = useHomePageFilter<Filter<string>[]>(
    'agentVersions',
    []
  );

  const groupsQuery = useGroups();

  const environmentsQueryParams: EnvironmentsQueryParams = {
    types: getTypes(
      platformTypes.map((p) => p.value),
      connectionTypes.map((p) => p.value)
    ),
    search: searchBarValue,
    status: statusFilter,
    tagIds: tagFilter?.length ? tagFilter : undefined,
    groupIds: groupFilter,
    provisioned: true,
    tagsPartialMatch: true,
    agentVersions: agentVersions.map((a) => a.value),
    updateInformation: isBE,
  };

  const queryWithSort = {
    ...environmentsQueryParams,
    sort: sortByFilter,
    order: sortByDescending ? 'desc' : ('asc' as 'desc' | 'asc'),
  };

  const {
    isLoading,
    environments,
    totalCount,
    totalAvailable,
    updateAvailable,
  } = useEnvironmentList(
    {
      page,
      pageLimit,
      ...queryWithSort,
    },
    refetchIfAnyOffline
  );

  useEffect(() => {
    setPage(1);
  }, [searchBarValue]);

  return (
    <>
      {totalAvailable === 0 && <NoEnvironmentsInfoPanel isAdmin={isAdmin} />}

      <TableContainer>
        <div className="px-4">
          <TableTitle
            className="!px-0"
            icon={HardDrive}
            label="Environments"
            description={
              <div className="w-full text-sm text-gray-7">
                Click on an environment to manage
              </div>
            }
          >
            <div className="flex gap-4 items-center">
              <SearchBar
                className="!bg-transparent !m-0 !min-w-[350px]"
                value={searchBarValue}
                onChange={setSearchBarValue}
                placeholder="Search by name, group, tag, status, URL..."
                data-cy="home-endpointsSearchInput"
              />
              {isAdmin && (
                <Button
                  onClick={onRefresh}
                  data-cy="home-refreshEndpointsButton"
                  size="medium"
                  color="light"
                  icon={RefreshCcw}
                  className="!m-0"
                >
                  Refresh
                </Button>
              )}
              <KubeconfigButton
                environments={environments}
                envQueryParams={queryWithSort}
              />

              <AMTButton
                environments={environments}
                envQueryParams={queryWithSort}
              />

              {updateAvailable && <UpdateBadge />}
            </div>
          </TableTitle>
          <div className="-mt-3">
            <EnvironmentListFilters
              setPlatformTypes={setPlatformTypes}
              platformTypes={platformTypes}
              setConnectionTypes={setConnectionTypes}
              connectionTypes={connectionTypes}
              statusOnChange={statusOnChange}
              statusState={statusState}
              tagOnChange={tagOnChange}
              tagState={tagState}
              groupOnChange={groupOnChange}
              groupState={groupState}
              setAgentVersions={setAgentVersions}
              agentVersions={agentVersions}
              clearFilter={clearFilter}
              sortOnchange={sortOnchange}
              sortOnDescending={sortOnDescending}
              sortByDescending={sortByDescending}
              sortByButton={sortByButton}
              sortByState={sortByState}
            />
          </div>
          <div
            className="blocklist !p-0 mt-5 !space-y-2"
            data-cy="home-endpointList"
          >
            {renderItems(
              isLoading,
              totalCount,
              environments.map((env) => (
                <EnvironmentItem
                  key={env.Id}
                  environment={env}
                  groupName={
                    groupsQuery.data?.find((g) => g.Id === env.GroupId)?.Name
                  }
                  onClickBrowse={() => onClickBrowse(env)}
                  onClickDisconnect={() =>
                    env.Id === currentEnvStore.environmentId
                      ? currentEnvStore.clear()
                      : null
                  }
                  isActive={env.Id === currentEnvStore.environmentId}
                />
              ))
            )}
          </div>
          <TableFooter>
            <PaginationControls
              className="!mr-0"
              showAll={totalCount <= 100}
              pageLimit={pageLimit}
              page={page}
              onPageChange={setPage}
              totalCount={totalCount}
              onPageLimitChange={setPageLimit}
            />
          </TableFooter>
        </div>
      </TableContainer>
    </>
  );

  function getTypes(
    platformTypes: PlatformType[],
    connectionTypes: ConnectionType[]
  ) {
    if (platformTypes.length === 0 && connectionTypes.length === 0) {
      return [];
    }

    const typesByPlatform = {
      [PlatformType.Docker]: [
        EnvironmentType.Docker,
        EnvironmentType.AgentOnDocker,
        EnvironmentType.EdgeAgentOnDocker,
      ],
      [PlatformType.Azure]: [EnvironmentType.Azure],
      [PlatformType.Kubernetes]: [
        EnvironmentType.KubernetesLocal,
        EnvironmentType.AgentOnKubernetes,
        EnvironmentType.EdgeAgentOnKubernetes,
      ],
      [PlatformType.Nomad]: [EnvironmentType.EdgeAgentOnNomad],
    };

    const typesByConnection = {
      [ConnectionType.API]: [
        EnvironmentType.Azure,
        EnvironmentType.KubernetesLocal,
        EnvironmentType.Docker,
      ],
      [ConnectionType.Agent]: [
        EnvironmentType.AgentOnDocker,
        EnvironmentType.AgentOnKubernetes,
      ],
      [ConnectionType.EdgeAgent]: EdgeTypes,
      [ConnectionType.EdgeDevice]: EdgeTypes,
    };

    const selectedTypesByPlatform = platformTypes.flatMap(
      (platformType) => typesByPlatform[platformType]
    );
    const selectedTypesByConnection = connectionTypes.flatMap(
      (connectionType) => typesByConnection[connectionType]
    );

    if (selectedTypesByPlatform.length === 0) {
      return selectedTypesByConnection;
    }

    if (selectedTypesByConnection.length === 0) {
      return selectedTypesByPlatform;
    }

    return _.intersection(selectedTypesByConnection, selectedTypesByPlatform);
  }

  function statusOnChange(filterOptions: Filter[]) {
    setStatusState(filterOptions);
    if (filterOptions.length === 0) {
      setStatusFilter([]);
    } else {
      const filteredStatus = [
        ...new Set(
          filterOptions.map(
            (filterOptions: { value: number }) => filterOptions.value
          )
        ),
      ];
      setStatusFilter(filteredStatus);
    }
  }

  function groupOnChange(filterOptions: Filter[]) {
    setGroupState(filterOptions);
    if (filterOptions.length === 0) {
      setGroupFilter([]);
    } else {
      const filteredGroups = [
        ...new Set(
          filterOptions.map(
            (filterOptions: { value: number }) => filterOptions.value
          )
        ),
      ];
      setGroupFilter(filteredGroups);
    }
  }

  function tagOnChange(filterOptions: Filter[]) {
    setTagState(filterOptions);
    if (filterOptions.length === 0) {
      setTagFilter([]);
    } else {
      const filteredTags = [
        ...new Set(
          filterOptions.map(
            (filterOptions: { value: number }) => filterOptions.value
          )
        ),
      ];
      setTagFilter(filteredTags);
    }
  }

  function clearFilter() {
    setPlatformTypes([]);
    setStatusState([]);
    setStatusFilter([]);
    setTagState([]);
    setTagFilter([]);
    setGroupState([]);
    setGroupFilter([]);
    setAgentVersions([]);
    setConnectionTypes([]);
  }

  function sortOnchange(filterOptions: Filter) {
    if (filterOptions !== null) {
      setSortByFilter(filterOptions.label);
      setSortByButton(true);
      setSortByState(filterOptions);
    } else {
      setSortByFilter('');
      setSortByButton(true);
      setSortByState(undefined);
    }
  }

  function sortOnDescending() {
    setSortByDescending(!sortByDescending);
  }
}

function renderItems(
  isLoading: boolean,
  totalCount: number,

  items: ReactNode
) {
  if (isLoading) {
    return (
      <div className="text-center text-muted" data-cy="home-loadingEndpoints">
        Loading...
      </div>
    );
  }

  if (!totalCount) {
    return (
      <div className="text-center text-muted" data-cy="home-noEndpoints">
        No environments available.
      </div>
    );
  }

  return items;
}
