<template>
  <div>
    <div class="sticky top-0 z-10 flex flex-col rounded-t bg-primary">
      <tippy
        v-if="environmentType.type === 'my-environments'"
        interactive
        trigger="click"
        theme="popover"
        arrow
        :on-shown="() => tippyActions!.focus()"
      >
        <span
          v-tippy="{ theme: 'tooltip' }"
          :title="`${t('environment.select')}`"
          class="bg-transparent border-b border-dividerLight select-wrapper"
        >
          <ButtonSecondary
            v-if="
              selectedEnv.type === 'MY_ENV' && selectedEnv.index !== undefined
            "
            :label="myEnvironments[selectedEnv.index].name"
            class="flex-1 !justify-start pr-8 rounded-none"
          />
          <ButtonSecondary
            v-else
            :label="`${t('environment.select')}`"
            class="flex-1 !justify-start pr-8 rounded-none"
          />
        </span>
        <template #content="{ hide }">
          <div
            ref="tippyActions"
            role="menu"
            class="flex flex-col focus:outline-none"
            tabindex="0"
            @keyup.escape="hide()"
          >
            <SmartItem
              :label="`${t('environment.no_environment')}`"
              :info-icon="
                selectedEnvironmentIndex.type !== 'MY_ENV'
                  ? IconCheck
                  : undefined
              "
              :active-info-icon="selectedEnvironmentIndex.type !== 'MY_ENV'"
              @click="
                () => {
                  selectedEnvironmentIndex = { type: 'NO_ENV_SELECTED' }
                  hide()
                }
              "
            />
            <hr v-if="myEnvironments.length > 0" />
            <SmartItem
              v-for="(gen, index) in myEnvironments"
              :key="`gen-${index}`"
              :label="gen.name"
              :info-icon="index === selectedEnv.index ? IconCheck : undefined"
              :active-info-icon="index === selectedEnv.index"
              @click="
                () => {
                  selectedEnvironmentIndex = { type: 'MY_ENV', index: index }
                  hide()
                }
              "
            />
          </div>
        </template>
      </tippy>
      <tippy v-else interactive trigger="click" theme="popover" arrow>
        <span
          v-tippy="{ theme: 'tooltip' }"
          :title="`${t('environment.select')}`"
          class="bg-transparent border-b border-dividerLight select-wrapper"
        >
          <ButtonSecondary
            v-if="selectedEnv.name"
            :label="selectedEnv.name"
            class="flex-1 !justify-start pr-8 rounded-none"
          />
          <ButtonSecondary
            v-else
            :label="`${t('environment.select')}`"
            class="flex-1 !justify-start pr-8 rounded-none"
          />
        </span>
        <template #content="{ hide }">
          <div
            class="flex flex-col"
            role="menu"
            tabindex="0"
            @keyup.escape="hide()"
          >
            <SmartItem
              :label="`${t('environment.no_environment')}`"
              :info-icon="
                selectedEnvironmentIndex.type !== 'TEAM_ENV'
                  ? IconCheck
                  : undefined
              "
              :active-info-icon="selectedEnvironmentIndex.type !== 'TEAM_ENV'"
              @click="
                () => {
                  selectedEnvironmentIndex = { type: 'NO_ENV_SELECTED' }
                  hide()
                }
              "
            />
            <div
              v-if="loading"
              class="flex flex-col items-center justify-center p-4"
            >
              <SmartSpinner class="my-4" />
              <span class="text-secondaryLight">{{ t("state.loading") }}</span>
            </div>
            <hr v-if="teamEnvironmentList.length > 0" />
            <div
              v-if="environmentType.selectedTeam !== undefined"
              class="flex flex-col"
            >
              <SmartItem
                v-for="(gen, index) in teamEnvironmentList"
                :key="`gen-team-${index}`"
                :label="gen.environment.name"
                :info-icon="
                  gen.id === selectedEnv.teamEnvID ? IconCheck : undefined
                "
                :active-info-icon="gen.id === selectedEnv.teamEnvID"
                @click="
                  () => {
                    selectedEnvironmentIndex = {
                      type: 'TEAM_ENV',
                      teamEnvID: gen.id,
                      teamID: gen.teamID,
                      environment: gen.environment,
                    }
                    hide()
                  }
                "
              />
            </div>
            <div
              v-if="!loading && adapterError"
              class="flex flex-col items-center py-4"
            >
              <i class="mb-4 material-icons">help_outline</i>
              {{ getErrorMessage(adapterError) }}
            </div>
          </div>
        </template>
      </tippy>
      <EnvironmentsChooseType
        :environment-type="environmentType"
        :show="showTeamEnvironment"
        @update-environment-type="updateEnvironmentType"
        @update-selected-team="updateSelectedTeam"
      />
    </div>
    <EnvironmentsMy v-if="environmentType.type === 'my-environments'" />
    <EnvironmentsTeams
      v-else
      :team="environmentType.selectedTeam"
      :team-environments="teamEnvironmentList"
      :loading="loading"
      :adapter-error="adapterError"
    />
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from "vue"
import { isEqual } from "lodash-es"
import { currentUser$ } from "~/helpers/fb/auth"
import { Team } from "~/helpers/backend/graphql"
import { useReadonlyStream, useStream } from "@composables/stream"
import { useI18n } from "~/composables/i18n"
import {
  environments$,
  selectedEnvironmentIndex$,
  setSelectedEnvironmentIndex,
} from "~/newstore/environments"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import { GQLError } from "~/helpers/backend/GQLClient"
import IconCheck from "~icons/lucide/check"
import { TippyComponent } from "vue-tippy"

const t = useI18n()

type EnvironmentType = "my-environments" | "team-environments"

type SelectedTeam = Team | undefined

type EnvironmentsChooseType = {
  type: EnvironmentType
  selectedTeam: SelectedTeam
}

const environmentType = ref<EnvironmentsChooseType>({
  type: "my-environments",
  selectedTeam: undefined,
})

const currentUser = useReadonlyStream(currentUser$, null)

const showTeamEnvironment = computed(() => {
  if (currentUser.value == null) {
    return false
  }
  return true
})

const updateSelectedTeam = (newSelectedTeam: SelectedTeam) => {
  environmentType.value.selectedTeam = newSelectedTeam
}
const updateEnvironmentType = (newEnvironmentType: EnvironmentType) => {
  environmentType.value.type = newEnvironmentType
}

const adapter = new TeamEnvironmentAdapter(undefined)
const adapterLoading = useReadonlyStream(adapter.loading$, false)
const adapterError = useReadonlyStream(adapter.error$, null)
const teamEnvironmentList = useReadonlyStream(adapter.teamEnvironmentList$, [])

const loading = computed(
  () => adapterLoading.value && teamEnvironmentList.value.length === 0
)

watch(
  () => environmentType.value.selectedTeam?.id,
  (newTeamID) => {
    adapter.changeTeamID(newTeamID)
  }
)

const myEnvironments = useReadonlyStream(environments$, [])

const selectedEnvironmentIndex = useStream(
  selectedEnvironmentIndex$,
  { type: "NO_ENV_SELECTED" },
  setSelectedEnvironmentIndex
)

/* Checking if there are any changes in the selected team environment when there are any updates
in the selected team environment list */
watch(
  () => teamEnvironmentList.value,
  (newTeamEnvironmentList) => {
    if (
      newTeamEnvironmentList.length > 0 &&
      selectedEnvironmentIndex.value.type === "TEAM_ENV"
    ) {
      const selectedEnv = newTeamEnvironmentList.find(
        (env) =>
          env.id ===
          (selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
            selectedEnvironmentIndex.value.teamEnvID)
      )

      if (selectedEnv) {
        // Checking if the currently selected environment is still the same after the new list is loaded
        const isChange = !isEqual(
          selectedEnvironmentIndex.value.environment,
          selectedEnv.environment
        )

        if (isChange) {
          selectedEnvironmentIndex.value = {
            type: "TEAM_ENV",
            teamEnvID: selectedEnv.id,
            teamID: selectedEnv.teamID,
            environment: selectedEnv.environment,
          }
        }
      }
    }
  },
  { deep: true }
)

const selectedEnv = computed(() => {
  if (selectedEnvironmentIndex.value.type === "MY_ENV") {
    return {
      type: "MY_ENV",
      index: selectedEnvironmentIndex.value.index,
    }
  } else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
    const teamEnv = teamEnvironmentList.value.find(
      (env) =>
        env.id ===
        (selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
          selectedEnvironmentIndex.value.teamEnvID)
    )
    if (teamEnv) {
      return {
        type: "TEAM_ENV",
        name: teamEnv.environment.name,
        teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
      }
    } else {
      selectedEnvironmentIndex.value = { type: "NO_ENV_SELECTED" }
      return { type: "NO_ENV_SELECTED" }
    }
  } else {
    selectedEnvironmentIndex.value = { type: "NO_ENV_SELECTED" }
    return { type: "NO_ENV_SELECTED" }
  }
})

const getErrorMessage = (err: GQLError<string>) => {
  if (err.type === "network_error") {
    return t("error.network_error")
  } else {
    switch (err.error) {
      case "team_environment/not_found":
        return t("team_environment.not_found")
      default:
        return t("error.something_went_wrong")
    }
  }
}

// Template refs
const tippyActions = ref<TippyComponent | null>(null)
</script>
