import { code } from 'dashboard/generated/controlplane';
import {
  createInfrastructure,
  createServices,
} from 'dashboard/generated/controlplane/twirp';
import * as _ from 'lodash';
import { TwirpHTTPError } from 'pbjs-twirp';
import { useEffect, useState } from 'react';
import { GetControlplaneEndpoint } from './env';

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

export const createIAMRole = async (
  serviceID: string,
  iamRole: twirp.IIAMRole,
  success: (s: twirp.IIAMRole) => void,
  error: (msg: string) => void,
) => {
  const client = createServices(GetControlplaneEndpoint());
  const req: twirp.ICreateIAMRoleReq = {
    serviceId: serviceID,
    iamRole,
  };
  try {
    const resp = await client.createIAMRole(req);
    if (_.isNil(resp.iamRole)) {
      throw new Error('unexpected nil in create response');
    }
    success(resp.iamRole);
  } catch (e) {
    if (e instanceof TwirpHTTPError) {
      error(e.msg);
    } else {
      error(e.message);
    }
  }
};

export const grantIAMRolePublishPermissions = async (
  eventType: string,
  iamRoleArn: string,
  environment: string,
  success: (s: twirp.IAuthorizedFieldPublisherGrant) => void,
  error: (msg: string) => void,
) => {
  const client = createInfrastructure(GetControlplaneEndpoint());
  const req: twirp.infrastructure.IAllowIAMRolePublishReq = {
    eventType,
    environment,
    iamRole: iamRoleArn,
  };
  try {
    await client.allowIAMRolePublish(req);
    success({
      eventType,
      environment,
      iamRole: {
        arn: iamRoleArn,
      },
    });
  } catch (e) {
    if (e instanceof TwirpHTTPError) {
      error(e.msg);
    } else {
      error(e.message);
    }
  }
};

export const grantIAMRoleSubscriberPermissions = async (
  eventType: string,
  iamRoleArn: string,
  environment: string,
  messageName: string,
  fieldName: string,
  success: (s: twirp.IAuthorizedFieldSubscriberGrant) => void,
  error: (msg: string) => void,
) => {
  const client = createInfrastructure(GetControlplaneEndpoint());
  const req: twirp.infrastructure.ICreateAuthorizedFieldSubscriberGrantReq = {
    eventType,
    environment,
    iamRole: iamRoleArn,
    authorizedField: {
      messageName,
      fieldName,
    },
  };
  try {
    await client.createAuthorizedFieldSubscriberGrant(req);
    success({
      eventType,
      environment,
      iamRole: {
        arn: iamRoleArn,
      },
      authorizedField: {
        messageName,
        fieldName,
      },
    });
  } catch (e) {
    if (e instanceof TwirpHTTPError) {
      error(e.msg);
    } else {
      error(e.message);
    }
  }
};

export const deleteIAMRolePublication = async (
  publisherGrant: twirp.IAuthorizedFieldPublisherGrant,
  success: (_publisherGrant: twirp.IAuthorizedFieldPublisherGrant) => void,
  error: (msg: string) => void,
) => {
  const client = createInfrastructure(GetControlplaneEndpoint());
  const req: twirp.infrastructure.IDeleteIAMRolePublicationReq = {
    eventType: publisherGrant.eventType,
    environment: publisherGrant.environment,
    iamRoleArn: _.get(publisherGrant, 'iamRole.arn', ''),
  };
  try {
    await client.deleteIAMRolePublication(req);
    success(publisherGrant);
  } catch (e) {
    if (e instanceof TwirpHTTPError) {
      error(e.msg);
    } else {
      error(e.message);
    }
  }
};

export const updateIAMRoleLabel = async (
  iamRole: twirp.IIAMRole,
  success: (s: twirp.IIAMRole) => void,
  error: (e: Error) => void,
) => {
  const client = createServices(GetControlplaneEndpoint());
  const req: twirp.IUpdateIAMRoleLabelReq = {
    arn: iamRole.arn,
    label: iamRole.label,
  };
  try {
    await client.updateIAMRoleLabel(req);
    success({
      arn: iamRole.arn,
      label: iamRole.label,
    });
  } catch (e) {
    error(e);
  }
};

export const useIAMRoleValidation = (arn: string) => {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);
  const [isValid, setIsValid] = useState(false);
  const [message, setMessage] = useState('');

  const client = createServices(GetControlplaneEndpoint());
  const req: twirp.IValidateIAMRoleReq = {
    arn,
  };

  useEffect(() => {
    const fetchData = async () => {
      if (!arn) {
        return {
          isValid,
          message,
          loading,
          error,
        };
      }
      try {
        const resp = await client.validateIAMRole(req);
        setIsValid(resp.isValid);
        setMessage(resp.message);
        setLoading(false);
      } catch (e) {
        setError(e);
        setLoading(false);
      }
    };
    fetchData();
  }, [arn]);

  return {
    isValid,
    message,
    loading,
    error,
  };
};

export const deleteIAMRole = async (
  arn: string,
  onSuccess: (arn: string) => void,
  onError: (_: Error) => void,
) => {
  const client = createServices(GetControlplaneEndpoint());
  const req: twirp.IDeleteIAMRoleReq = {
    arn,
  };
  try {
    await client.deleteIAMRole(req);
    onSuccess(arn);
  } catch (e) {
    onError(e);
  }
};
