import { code } from 'dashboard/generated/controlplane';
import { createTargets } 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 useTarget = (serviceId: string, targetId: string) => {
  const [target, setTarget] = useState<twirp.ITarget>(new twirp.Target());
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);
  const [forbidden, setForbidden] = useState(false);

  const getTargetsForServiceReq = new twirp.GetTargetsForServiceReq({
    serviceId,
  });

  const client = createTargets(GetControlplaneEndpoint());

  useEffect(() => {
    if (!serviceId || !targetId) {
      return;
    }
    const fetchData = async () => {
      try {
        const s = await client.getTargetsForService(getTargetsForServiceReq);
        const foundTarget = _.find(s.targets, (t) => t.id === targetId);
        if (_.isNil(foundTarget)) {
          throw new Error('target not found');
        }
        setTarget(foundTarget);
        setLoading(false);
      } catch (err) {
        if (
          err instanceof TwirpHTTPError &&
          (err as TwirpHTTPError).status === 403
        ) {
          setLoading(false);
          setForbidden(true);
        } else {
          setLoading(false);
          setError(err);
        }
      }
    };
    fetchData();
  }, [serviceId, targetId]);

  return { target, loading, error, forbidden };
};

export const useServiceTargets = (serviceId: string) => {
  const [targets, setTargets] = useState<Array<twirp.ITarget>>(
    new Array<twirp.ITarget>(),
  );
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);
  const [forbidden, setForbidden] = useState(false);

  const getTargetsForServiceReq = new twirp.GetTargetsForServiceReq({
    serviceId,
  });

  const client = createTargets(GetControlplaneEndpoint());

  useEffect(() => {
    if (!serviceId) {
      return;
    }
    const fetchData = async () => {
      try {
        const s = await client.getTargetsForService(getTargetsForServiceReq);
        setTargets(s.targets);
        setLoading(false);
      } catch (err) {
        if (
          err instanceof TwirpHTTPError &&
          (err as TwirpHTTPError).status === 403
        ) {
          setLoading(false);
          setForbidden(true);
        } else {
          setLoading(false);
          setError(err);
        }
      }
    };
    fetchData();
  }, [serviceId]);

  return { targets, loading, error, forbidden };
};

export const registerTarget = async (
  target: twirp.ITarget,
  onSuccess: (_: twirp.ITarget) => void,
  onError: (_: Error) => void,
) => {
  const client = createTargets(GetControlplaneEndpoint());
  const req: twirp.ICreateTargetReq = _.extend(target, {
    type: twirp.TargetType.TARGET_TYPE_SQS,
  });
  try {
    const resp = await client.create(req);
    if (resp.target) {
      onSuccess(resp.target);
    }
  } catch (e) {
    onError(e);
  }
};

export const deregisterTarget = async (
  target: twirp.ITarget,
  onSuccess: (_: twirp.ITarget) => void,
  onError: (_: Error) => void,
) => {
  const client = createTargets(GetControlplaneEndpoint());
  const req: twirp.IDeleteTargetReq = {
    subscriptionTargetId: target.id,
  };
  try {
    await client.delete(req);
    onSuccess(target);
  } catch (e) {
    onError(e);
  }
};

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

  const client = createTargets(GetControlplaneEndpoint());
  const req: twirp.IValidateTargetReq = {
    sqsQueueUrl: queueURL,
  };

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

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