import { isEmpty } from 'lodash';
import React from 'react';
import { from as observableFrom, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import type { Application, IFunction, IOverridableProps } from '@spinnaker/core';
import { AccountTag, CollapsibleSection, Details, Overrides } from '@spinnaker/core';

import { FunctionActions } from './FunctionActions';
import type { IAmazonFunction, IAmazonFunctionSourceData } from '../../domain';
import { AwsReactInjector } from '../../reactShims';

export interface IFunctionFromStateParams {
  account: string;
  region: string;
  functionName: string;
}

export interface IAmazonFunctionDetailsProps extends IOverridableProps {
  app: Application;
  functionObj: IFunction;
}

@Overrides('function.details', 'aws')
export class AmazonFunctionDetails extends React.Component<IAmazonFunctionDetailsProps, any> {
  private destroy$ = new Subject();
  constructor(props: IAmazonFunctionDetailsProps) {
    super(props);
    this.state = {
      loading: true,
    };
  }

  public extractFunction(): void {
    const { app, functionObj: functionFromProps } = this.props;
    const functionDef: IFunction = app.functions.data.find((test: IFunction) => {
      return (
        test.functionName === functionFromProps.functionName &&
        test.region === functionFromProps.region &&
        test.account === functionFromProps.account
      );
    });

    if (functionDef) {
      observableFrom(
        AwsReactInjector.functionReader.getFunctionDetails(
          'aws',
          functionFromProps.account,
          functionFromProps.region,
          functionFromProps.functionName,
        ),
      )
        .pipe(takeUntil(this.destroy$))
        .subscribe((details: IAmazonFunctionSourceData[]) => {
          if (details.length) {
            this.setState({
              functionDef: details[0] as IAmazonFunction,
              loading: false,
            });
          }
        });
    } else {
      this.setState({
        functionDef: {},
        loading: false,
      });
    }
  }

  public componentDidMount(): void {
    const { app } = this.props;
    const dataSource = app.functions;
    observableFrom(dataSource.ready())
      .pipe(takeUntil(this.destroy$))
      .subscribe(() => {
        const dataSourceUnsubscribe = dataSource.onRefresh(null, () => this.extractFunction());
        this.setState({ dataSourceUnsubscribe });
        this.extractFunction();
      });
  }

  public componentWillUnmount() {
    this.state.dataSourceUnsubscribe && this.state.dataSourceUnsubscribe();
    this.destroy$.next();
  }

  public render() {
    const { app } = this.props;
    const { loading, functionDef } = this.state;
    if (loading) {
      // Don't bother computing any children if we're loading
      return <Details loading={loading} />;
    }

    const functionDetails = (
      <dl className="horizontal-when-filters-collapsed dl-horizontal dl-narrow">
        <dt>Last Modified </dt>
        <dd>{functionDef.lastModified}</dd>
        <dt>In</dt>
        <dd>
          <AccountTag account={functionDef.account} /> {functionDef.region}
        </dd>
        <dt>VPC</dt>
        <dd>{functionDef.vpcConfig ? functionDef.vpcConfig.vpcId : 'Default'}</dd>
        <dt>Function ARN</dt>
        <dd>{functionDef.functionArn}</dd>
        <dt>Revision ID</dt>
        <dd>{functionDef.revisionId}</dd>
        <dt>Version</dt>
        <dd>{functionDef.version}</dd>
      </dl>
    );

    const eventSourceDetails = (
      <dl className="horizontal-when-filters-collapsed dl-horizontal dl-narrow">
        {functionDef.eventSourceMappings && functionDef.eventSourceMappings.length !== 0
          ? functionDef.eventSourceMappings.map((value: any) => (
              <>
                <h5>
                  <strong>Event Source</strong>
                </h5>
                <dl>
                  <dt>ARN</dt>
                  <dd>{value.eventSourceArn}</dd>
                  <dt>State</dt>
                  <dd>{value.state}</dd>
                </dl>
              </>
            ))
          : 'None'}
      </dl>
    );

    const aliasConfigurationDetails = (
      <dl className="horizontal-when-filters-collapsed dl-horizontal dl-narrow">
        {functionDef.aliasConfigurations && functionDef.aliasConfigurations.length !== 0
          ? functionDef.aliasConfigurations.map((value: any) => (
              <>
                <h5>
                  <strong>Alias Details</strong>
                </h5>
                <dl>
                  <dt>Name</dt>
                  <dd>{value.name}</dd>
                  <dt>ARN</dt>
                  <dd>{value.aliasArn}</dd>
                </dl>
              </>
            ))
          : 'None'}
      </dl>
    );

    const functionDetailsSection = (
      <CollapsibleSection heading="Function Details">{functionDetails}</CollapsibleSection>
    );

    const eventSourceDetailsSection = (
      <CollapsibleSection heading="Event Source Details">{eventSourceDetails}</CollapsibleSection>
    );

    const aliasConfigurationDetailsSection = (
      <CollapsibleSection heading="Alias Configuration Details">{aliasConfigurationDetails}</CollapsibleSection>
    );

    return (
      <Details loading={this.state.loading}>
        {isEmpty(this.state.functionDef) ? (
          'Function not found.'
        ) : (
          <Details.Header
            icon={<i className="fa fa-xs fa-fw fa-asterisk" />}
            name={this.state.functionDef.functionName}
          >
            <div className="actions">
              <FunctionActions
                app={app}
                functionDef={functionDef}
                functionFromParams={{
                  account: this.state.functionDef.account,
                  region: this.state.functionDef.region,
                  functionName: this.state.functionDef.functionName,
                }}
              />
            </div>
          </Details.Header>
        )}
        {!isEmpty(this.state.functionDef) ? functionDetailsSection : ''}
        {!isEmpty(this.state.functionDef) && !isEmpty(this.state.functionDef.eventSourceMappings)
          ? eventSourceDetailsSection
          : ''}
        {!isEmpty(this.state.functionDef) && !isEmpty(this.state.functionDef.aliasConfigurations)
          ? aliasConfigurationDetailsSection
          : ''}
      </Details>
    );
  }
}
