import { Errored } from 'dashboard/core/components/errored';
import { ModalContext } from 'dashboard/core/contexts/modals';
import { useProductionEventStreams } from 'dashboard/core/utils/event-stream';
import { useLDAPGroups } from 'dashboard/core/utils/ldap';
import { code } from 'dashboard/generated/controlplane';
import { EventDetailsModal } from 'dashboard/pages/subscriptions/components/event-details-modal';
import * as _ from 'lodash';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import {
  Button,
  ButtonSize,
  ButtonType,
  Color,
  Column,
  CoreLink,
  CoreText,
  Display,
  FlexDirection,
  FontSize,
  FontWeight,
  Grid,
  GridGutterSize,
  Input,
  InputSize,
  InputType,
  Layout,
  LineHeight,
  LoadingSpinner,
  Overflow,
  StyledLayout,
  SVGAsset,
  TextAlign,
  TextTransform,
  TextType,
} from 'twitch-core-ui';

import twirp = code.justin.tv.eventbus.controlplane;

export const EventCatalog = () => {
  const { eventType } = useParams();
  const history = useHistory();
  const {
    productionEventStreams,
    loading,
    error,
  } = useProductionEventStreams();

  const [searchTerm, setSearchTerm] = useState('');
  const handleSearchTermChange = (e: React.FormEvent<HTMLInputElement>) => {
    setSearchTerm(e.currentTarget.value || '');
  };

  const { ldapGroups, loading: ldapLoading, error: ldapError } = useLDAPGroups();

  const ownedEventTypes = new Map<string, Array<twirp.IEventStream>>();
  let otherEventTypes = new Array<twirp.IEventStream>();
  _.forEach(productionEventStreams, (e: twirp.IEventStream) => {
    if (
      searchTerm === '' ||
      (e.displayName as string)
        .toLowerCase()
        .includes(searchTerm.toLocaleLowerCase())
    ) {
      if (_.includes(ldapGroups, e.ldapGroup)) {
        const eventTypesForLDAPGroup = ownedEventTypes.get(
          e.ldapGroup as string,
        );
        if (_.isNil(eventTypesForLDAPGroup)) {
          ownedEventTypes.set(e.ldapGroup as string, [e]);
        } else {
          ownedEventTypes.set(
            e.ldapGroup as string,
            eventTypesForLDAPGroup.concat(e).sort(),
          );
        }
      } else {
        otherEventTypes.push(e);
      }
    }
  });

  otherEventTypes = _.sortBy(otherEventTypes, 'displayName');

  const { showModal } = React.useContext(ModalContext);
  const handleShowEventDetailsModal = (eventStream: twirp.IEventStream) => {
    showModal({
      component: EventDetailsModal,
      props: {
        eventStream,
      },
      onHide: () => history.push('/events'),
    });
  };
  const handleEventManage = (eventStream: twirp.IEventStream) => {
    return () => {
      history.push(`/events/${eventStream.displayName}/manage`);
    };
  };

  const handleEventSelect = (eventStream: twirp.IEventStream) => {
    return () => {
      history.push(`/events/${eventStream.displayName}`);
    };
  };
  useEffect(() => {
    if (eventType !== '' && productionEventStreams) {
      _.forEach(productionEventStreams, (eventStream: twirp.IEventStream) => {
        if (eventStream.displayName === eventType) {
          handleShowEventDetailsModal(eventStream);
        }
      });
    }
  }, [eventType, loading]);

  if (loading || ldapLoading) {
    return <LoadingSpinner />;
  } else if (error) {
    return <Errored text={error.message} />;
  } else if (ldapError) {
    return <Errored text={ldapError.message} />;
  }

  return (
    <>
      <StyledLayout margin={{ top: 1, bottom: 1 }}>
        <CoreText type={TextType.H3}>Event Catalog</CoreText>
      </StyledLayout>
      <StyledLayout margin={{ top: 1, bottom: 1 }}>
        <Input
          icon={SVGAsset.NavSearch}
          size={InputSize.Default}
          type={InputType.Text}
          placeholder="Search for events"
          onChange={handleSearchTermChange}
        />
      </StyledLayout>
      <StyledLayout elevation={1}>
        <Grid gutterSize={GridGutterSize.None}>
          <Column cols={{ md: 6, default: 12 }}>
            <Grid>
              <Column cols={12}>
                <StyledLayout padding={1}>
                  <CoreText
                    fontSize={FontSize.Size4}
                    lineHeight={LineHeight.Heading}
                    fontWeight={FontWeight.SemiBold}
                  >
                    My Events
                  </CoreText>
                </StyledLayout>
              </Column>
              <Column cols={12}>
                <StyledLayout
                  fullHeight
                  overflow={Overflow.Hidden}
                  display={Display.Flex}
                  flexDirection={FlexDirection.Column}
                  padding={1}
                >
                  {_.map(Array.from(ownedEventTypes.keys()), (ldapGroup) => (
                    <LDAPGroupEventList
                      ldapGroup={ldapGroup}
                      events={
                        ownedEventTypes.get(ldapGroup) ||
                        new Array<twirp.IEventStream>()
                      }
                      onEventSelect={handleEventSelect}
                      onEventManage={handleEventManage}
                    />
                  ))}
                  {ownedEventTypes.size === 0 && (
                    <StyledLayout padding={{ x: 2 }}>
                      <CoreText type={TextType.P} color={Color.Alt2}>
                        No events owned by your LDAP groups to display. See{' '}
                        <CoreLink
                          targetBlank
                          linkTo="https://git.xarth.tv/pages/eventbus/docs/schema/event_type_ownership/"
                        >
                          the docs
                        </CoreLink>{' '}
                        for information on event type ownership
                      </CoreText>
                    </StyledLayout>
                  )}
                </StyledLayout>
              </Column>
            </Grid>
          </Column>
          <Column cols={{ md: 6, default: 12 }}>
            <StyledLayout borderLeft fullHeight flexGrow={1}>
              <Grid gutterSize={GridGutterSize.None}>
                <Column cols={12}>
                  <StyledLayout padding={1}>
                    <CoreText
                      fontSize={FontSize.Size4}
                      lineHeight={LineHeight.Heading}
                      fontWeight={FontWeight.SemiBold}
                    >
                      Other Events
                    </CoreText>
                  </StyledLayout>
                </Column>
                {_.map(otherEventTypes, (eventStream) => (
                  <Column cols={12}>
                    <StyledLayout
                      overflow={Overflow.Hidden}
                      padding={{ x: 2, y: 0.5 }}
                    >
                      <Button
                        size={ButtonSize.Large}
                        type={ButtonType.Text}
                        onClick={handleEventSelect(eventStream)}
                      >
                        {eventStream.deprecated
                          ? `${eventStream.displayName} (deprecated)`
                          : `${eventStream.displayName}`}
                      </Button>
                    </StyledLayout>
                  </Column>
                ))}
                {otherEventTypes.length === 0 && (
                  <Column cols={12}>
                    <StyledLayout
                      padding={{ x: 2 }}
                      textAlign={TextAlign.Center}
                    >
                      <CoreText type={TextType.P} color={Color.Alt2}>
                        No event types match the search term
                      </CoreText>
                    </StyledLayout>
                  </Column>
                )}
              </Grid>
            </StyledLayout>
          </Column>
        </Grid>
      </StyledLayout>
    </>
  );
};

interface LDAPGroupEventListProps {
  ldapGroup: string;
  events: twirp.IEventStream[];
  onEventSelect: (_: twirp.IEventStream) => () => void;
  onEventManage: (_: twirp.IEventStream) => () => void;
}

const LDAPGroupEventList = ({
  ldapGroup,
  events,
  onEventSelect,
  onEventManage,
}: LDAPGroupEventListProps) => (
  <Layout>
    <StyledLayout padding={{ x: 2, y: 0.5 }}>
      <CoreText
        fontWeight={FontWeight.SemiBold}
        fontSize={FontSize.Size6}
        transform={TextTransform.Uppercase}
      >
        {ldapGroup}
      </CoreText>
    </StyledLayout>
    {_.map(events as twirp.IEventStream[], (eventStream) => (
      <StyledLayout padding={{ y: 0.5, x: 2 }}>
        <Button
          size={ButtonSize.Large}
          type={ButtonType.Text}
          onClick={onEventSelect(eventStream)}
        >
          {eventStream.deprecated
            ? `${eventStream.displayName} (deprecated)`
            : `${eventStream.displayName}`}
        </Button>
        <Button
          size={ButtonSize.Small}
          type={ButtonType.Secondary}
          icon={SVGAsset.Gear}
          onClick={onEventManage(eventStream)}
        />
      </StyledLayout>
    ))}
  </Layout>
);
