<script lang="ts" setup>
import type { ProjectType } from 'nocodb-sdk'
import tinycolor from 'tinycolor2'
import { breakpointsTailwind } from '@vueuse/core'
import {
  Empty,
  Modal,
  computed,
  definePageMeta,
  extractSdkResponseErrorMsg,
  message,
  navigateTo,
  onBeforeMount,
  projectThemeColors,
  ref,
  themeV2Colors,
  useApi,
  useBreakpoints,
  useCopy,
  useGlobal,
  useNuxtApp,
  useUIPermission,
} from '#imports'

definePageMeta({
  title: 'title.myProject',
})

const { $api, $e } = useNuxtApp()

const { api, isLoading } = useApi()

const { isUIAllowed } = useUIPermission()

const { md } = useBreakpoints(breakpointsTailwind)

const filterQuery = ref('')

const projects = ref<ProjectType[]>()

const { appInfo } = useGlobal()

const loadProjects = async () => {
  const response = await api.project.list({})
  projects.value = response.list
}

const filteredProjects = computed(
  () =>
    projects.value?.filter(
      (project) => !filterQuery.value || project.title?.toLowerCase?.().includes(filterQuery.value.toLowerCase()),
    ) ?? [],
)

const deleteProject = (project: ProjectType) => {
  $e('c:project:delete')

  Modal.confirm({
    title: `Do you want to delete '${project.title}' project?`,
    wrapClassName: 'nc-modal-project-delete',
    okText: 'Yes',
    okType: 'danger',
    cancelText: 'No',
    async onOk() {
      try {
        await api.project.delete(project.id as string)

        $e('a:project:delete')

        projects.value?.splice(projects.value?.indexOf(project), 1)
      } catch (e: any) {
        message.error(await extractSdkResponseErrorMsg(e))
      }
    },
  })
}

const handleProjectColor = async (projectId: string, color: string) => {
  const tcolor = tinycolor(color)

  if (tcolor.isValid()) {
    const complement = tcolor.complement()

    const project: ProjectType = await $api.project.read(projectId)

    const meta = project?.meta && typeof project.meta === 'string' ? JSON.parse(project.meta) : project.meta || {}

    await $api.project.update(projectId, {
      color,
      meta: JSON.stringify({
        ...meta,
        theme: {
          primaryColor: color,
          accentColor: complement.toHex8String(),
        },
      }),
    })

    // Update local project
    const localProject = projects.value?.find((p) => p.id === projectId)

    if (localProject) {
      localProject.color = color

      localProject.meta = JSON.stringify({
        ...meta,
        theme: {
          primaryColor: color,
          accentColor: complement.toHex8String(),
        },
      })
    }
  }
}

const getProjectPrimary = (project: ProjectType) => {
  if (!project) return

  const meta = project.meta && typeof project.meta === 'string' ? JSON.parse(project.meta) : project.meta || {}

  return meta.theme?.primaryColor || themeV2Colors['royal-blue'].DEFAULT
}

const customRow = (record: ProjectType) => ({
  onClick: async () => {
    if (record.type === 'docs') {
      await navigateTo(`/nc/doc/${record.id}`)
    } else {
      await navigateTo(`/nc/${record.id}`)
    }

    $e('a:project:open')
  },
  class: ['group'],
})

onBeforeMount(loadProjects)

const { copy } = useCopy()

const copyProjectMeta = async () => {
  const aggregatedMetaInfo = await $api.utils.aggregatedMetaInfo()
  copy(JSON.stringify(aggregatedMetaInfo))
  message.info('Copied aggregated project meta to clipboard')
}
</script>

<template>
  <div
    class="relative flex flex-col justify-center gap-2 w-full p-8 md:(bg-white rounded-lg border-1 border-gray-200 shadow)"
    data-testid="projects-container"
  >
    <h1 class="flex items-center justify-center gap-2 leading-8 mb-8 mt-4">
      <span class="text-4xl nc-project-page-title" @dblclick="copyProjectMeta">{{ $t('title.myProject') }}</span>
    </h1>

    <div class="flex flex-wrap gap-2 mb-6">
      <a-input-search
        v-model:value="filterQuery"
        class="max-w-[250px] nc-project-page-search rounded"
        :placeholder="$t('activity.searchProject')"
      />

      <a-tooltip title="Reload projects">
        <div
          class="transition-all duration-200 h-full flex-0 flex items-center group hover:ring active:(ring ring-accent) rounded-full mt-1"
          :class="isLoading ? 'animate-spin ring ring-gray-200' : ''"
        >
          <MdiRefresh
            v-e="['a:project:refresh']"
            class="text-xl text-gray-500 group-hover:text-accent cursor-pointer"
            :class="isLoading ? '!text-primary' : ''"
            data-testid="projects-reload-button"
            @click="loadProjects"
          />
        </div>
      </a-tooltip>

      <div class="flex-1" />

      <a-dropdown v-if="isUIAllowed('projectCreate', true)" :trigger="['click']" overlay-class-name="nc-dropdown-create-project">
        <button class="nc-new-project-menu mt-4 md:mt-0">
          <span class="flex items-center w-full">
            {{ $t('title.newProj') }}
            <MdiMenuDown class="menu-icon" />
          </span>
        </button>

        <template #overlay>
          <a-menu class="!py-0 rounded">
            <a-menu-item>
              <div
                v-e="['c:project:create:xcdb']"
                class="nc-project-menu-item group nc-create-xc-db-project"
                @click="navigateTo('/create')"
              >
                <MdiPlusOutline class="group-hover:text-accent" />

                <div>{{ $t('activity.createProject') }}</div>
              </div>
            </a-menu-item>

            <a-menu-item v-if="appInfo.connectToExternalDB">
              <div
                v-e="['c:project:create:extdb']"
                class="nc-project-menu-item group nc-create-external-db-project"
                @click="navigateTo('/create-external')"
              >
                <MdiDatabaseOutline class="group-hover:text-accent" />

                <div v-html="$t('activity.createProjectExtended.extDB')" />
              </div>
            </a-menu-item>
          </a-menu>
        </template>
      </a-dropdown>
    </div>

    <!--
      TODO: bring back transition after fixing the bug with navigation
      <Transition name="layout" mode="out-in"> -->
    <div v-if="isLoading">
      <a-skeleton />
    </div>

    <a-table
      v-else
      :custom-row="customRow"
      :data-source="filteredProjects"
      :pagination="{ position: ['bottomCenter'] }"
      :table-layout="md ? 'auto' : 'fixed'"
    >
      <template #emptyText>
        <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" :description="$t('labels.noData')" />
      </template>

      <!-- Title -->
      <a-table-column key="title" :title="$t('general.title')" data-index="title">
        <template #default="{ text, record }">
          <div class="flex items-center">
            <div @click.stop>
              <a-menu class="!border-0 !m-0 !p-0" trigger-sub-menu-action="click">
                <template v-if="isUIAllowed('projectTheme')">
                  <a-sub-menu key="theme" popup-class-name="custom-color">
                    <template #title>
                      <div
                        class="color-selector"
                        :style="{
                          'background-color': getProjectPrimary(record),
                          'width': '8px',
                          'height': '100%',
                        }"
                      />
                    </template>

                    <template #expandIcon></template>

                    <LazyGeneralColorPicker
                      :model-value="getProjectPrimary(record)"
                      :colors="projectThemeColors"
                      :row-size="9"
                      :advanced="false"
                      @input="handleProjectColor(record.id, $event)"
                    />

                    <a-sub-menu key="pick-primary">
                      <template #title>
                        <div class="nc-project-menu-item group !py-0">
                          <ClarityColorPickerSolid class="group-hover:text-accent" />
                          Custom Color
                        </div>
                      </template>

                      <template #expandIcon></template>

                      <LazyGeneralChromeWrapper @input="handleProjectColor(record.id, $event)" />
                    </a-sub-menu>
                  </a-sub-menu>
                </template>
              </a-menu>
            </div>
            <div
              class="capitalize color-transition group-hover:text-primary !w-[400px] h-full overflow-hidden overflow-ellipsis whitespace-nowrap pl-2"
            >
              {{ text }}
            </div>
          </div>
        </template>
      </a-table-column>
      <!-- Actions -->

      <a-table-column key="id" :title="$t('labels.actions')" data-index="id">
        <template #default="{ text, record }">
          <div class="flex items-center gap-2">
            <MdiEditOutline v-e="['c:project:edit:rename']" class="nc-action-btn" @click.stop="navigateTo(`/${text}`)" />

            <MdiDeleteOutline
              class="nc-action-btn"
              :data-testid="`delete-project-${record.title}`"
              @click.stop="deleteProject(record)"
            />
          </div>
        </template>
      </a-table-column>
    </a-table>
    <!--    </Transition> -->
  </div>
</template>

<style scoped>
.nc-action-btn {
  @apply text-gray-500 group-hover:text-accent active:(ring ring-accent ring-opacity-100) cursor-pointer p-2 w-[30px] h-[30px] hover:bg-gray-300/50 rounded-full;
}

.nc-new-project-menu {
  @apply cursor-pointer z-1 relative color-transition rounded-md px-3 py-2 text-white;

  &::after {
    @apply ring-opacity-100 rounded-md absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary bg-opacity-100;
    content: '';
    z-index: -1;
  }

  &:hover::after {
    @apply transform scale-110;
  }
}

:deep(.ant-table-cell) {
  @apply py-1;
}

:deep(.ant-table-row) {
  @apply cursor-pointer;
}

:deep(.ant-table) {
  @apply min-h-[428px];
}

:deep(.ant-menu-submenu-title) {
  @apply !p-0 !mr-1 !my-0 !h-5;
}

.color-selector:hover {
  filter: brightness(1.5);
}
</style>

<style>
.custom-color .ant-menu-submenu-title {
  height: auto !important;
}
</style>
