<script setup lang="ts">
import { SongAuthorInfo, SongFrom, SongLanguage, SongsInfo, UserInfo } from '@/api/api-models'
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
import { SONG_API_URL } from '@/data/constants'
import { refDebounced, useDebounceFn, useLocalStorage } from '@vueuse/core'
import { List } from 'linqts'
import {
  DataTableBaseColumn,
  DataTableColumns,
  FormInst,
  FormRules,
  NAvatar,
  NButton,
  NCard,
  NCollapseTransition,
  NDataTable,
  NDivider,
  NEllipsis,
  NForm,
  NFormItem,
  NIcon,
  NInput,
  NList,
  NListItem,
  NModal,
  NPopconfirm,
  NSelect,
  NSpace,
  NTag,
  NText,
  NTooltip,
  useMessage,
} from 'naive-ui'
import { onMounted, h, ref, watch, computed, reactive } from 'vue'
import APlayer from 'vue3-aplayer'
import { NotepadEdit20Filled, Delete24Filled, Play24Filled, SquareArrowForward24Filled } from '@vicons/fluent'
import NeteaseIcon from '@/svgs/netease.svg'
import FiveSingIcon from '@/svgs/fivesing.svg'

const props = defineProps<{
  songs: SongsInfo[]
  canEdit?: boolean
  isSelf: boolean
}>()
watch(
  () => props.songs,
  (newV) => {
    songsInternal.value = newV
    setTimeout(() => {
      columns.value = createColumns()
    }, 1)
  }
)
const volume = useLocalStorage('Settings.AplayerVolume', 0.8)
const songsInternal = ref(props.songs)
const songsComputed = computed(() => {
  if (debouncedInput.value) {
    //忽略大小写比较
    return songsInternal.value.filter((s) => s.name.toLowerCase().includes(debouncedInput.value.toLowerCase()))
  }
  return songsInternal.value
})
const message = useMessage()

const showModal = ref(false)
const updateSongModel = ref<SongsInfo>({} as SongsInfo)
const searchMusicKeyword = ref()
const debouncedInput = refDebounced(searchMusicKeyword, 500)

const aplayerMusic = ref<{
  title: string
  artist: string
  src: string
  lrc: string
}>()

const formRef = ref<FormInst | null>(null)
const updateSongRules: FormRules = {
  name: [
    {
      required: true,
      message: '请输入歌曲名称',
    },
  ],
  password: [
    {
      required: true,
      message: '请输入密码',
    },
  ],
}
const songSelectOption = [
  {
    label: '中文',
    value: SongLanguage.Chinese,
  },
  {
    label: '日语',
    value: SongLanguage.Japanese,
  },
  {
    label: '英语',
    value: SongLanguage.English,
  },
  {
    label: '法语',
    value: SongLanguage.French,
  },
  {
    label: '西语',
    value: SongLanguage.Spanish,
  },
  {
    label: '其他',
    value: SongLanguage.Other,
  },
]
const tagsSelectOption = computed(() => {
  return new List(songsInternal.value)
    .SelectMany((s) => new List(s?.tags))
    .Distinct()
    .ToArray()
    .map((t) => ({
      label: t,
      value: t,
    }))
})
const authorsOptions = computed(() => {
  return new List(songsInternal.value)
    .SelectMany((s) => new List(s?.author))
    .Distinct()
    .ToArray()
    .map((t) => ({
      label: t,
      value: t,
    }))
})

const columns = ref<DataTableColumns<SongsInfo>>()
const authorColumn = ref<DataTableBaseColumn<SongsInfo>>({
  title: '作者',
  key: 'artist',
  width: 200,
  resizable: true,
  filter(value, row) {
    return (row.author?.findIndex((t) => t == value.toString()) ?? -1) > -1
  },
  filterOptions: authorsOptions.value,
  render(data) {
    return h(NSpace, { size: 5 }, () => data.author.map((a) => h(NButton, { size: 'tiny', type: 'info', secondary: true, onClick: () => onAuthorClick(a) }, () => a)))
  },
})
const onAuthorClick = (author: string) => {
  if (authorColumn.value.filterOptionValue == author) {
    authorColumn.value.filterOptionValue = undefined
  } else {
    authorColumn.value.filterOptionValue = author
  }
}

function createColumns(): DataTableColumns<SongsInfo> {
  authorColumn.value.filterOptions = authorsOptions.value
  return [
    {
      key: 'name',
      resizable: true,
      minWidth: 100,
      width: 300,
      sorter: 'default',
      render(data) {
        return h(NSpace, { size: 5 }, () => [h(NText, () => data.name), h(NText, { depth: '3' }, () => data.translateName)])
      },
      title: '曲名',
    },
    authorColumn.value,
    {
      title: '语言',
      key: 'language',
      width: 150,
      resizable: true,
      filterOptions: songSelectOption,
      filter(value, row) {
        return (row.language?.findIndex((t) => t == (value.toString() as unknown as SongLanguage)) ?? -1) > -1
      },
      render(data) {
        return (data.language?.length ?? 0) > 0
          ? h(NSpace, { size: 5 }, () => data.language?.map((a) => h(NTag, { bordered: false, size: 'small' }, () => songSelectOption.find((s) => s.value == a)?.label)))
          : null
      },
    },
    {
      title: '描述',
      key: 'description',
      resizable: true,
      render(data) {
        return h(NEllipsis, () => data.description)
      },
    },
    {
      title: '标签',
      key: 'tags',
      resizable: true,
      filter(value, row) {
        return (row.tags?.findIndex((t) => t == value.toString()) ?? -1) > -1
      },
      filterOptions: tagsSelectOption.value,
      render(data) {
        return (data.tags?.length ?? 0) > 0 ? h(NSpace, { size: 5 }, () => data.tags?.map((a) => h(NTag, { bordered: false, size: 'small' }, () => a))) : null
      },
    },
    {
      title: '操作',
      key: 'manage',
      disabled: () => !props.canEdit,
      width: props.isSelf ? 170 : 100,
      render(data) {
        return h(
          NSpace,
          {
            justify: 'end',
            size: 10,
          },
          () => [
            GetPlayButton(data),
            data.url?.endsWith('mp3') || data.url?.endsWith('flac') || data.url?.endsWith('ogg') || data.url?.endsWith('wav') || data.url?.endsWith('m4a')
              ? h(NTooltip, null, {
                  trigger: () =>
                    h(
                      NButton,
                      {
                        type: 'primary',
                        size: 'small',
                        circle: true,
                        onClick: () => OnPlayMusic(data),
                      },
                      {
                        icon: () => h(NIcon, { component: Play24Filled }),
                      }
                    ),
                  default: () => '试听',
                })
              : null,
            props.isSelf
              ? [
                  h(NTooltip, null, {
                    trigger: () =>
                      h(
                        NButton,
                        {
                          size: 'small',
                          circle: true,
                          secondary: true,
                          onClick: () => {
                            updateSongModel.value = JSON.parse(JSON.stringify(data))
                            showModal.value = true
                          },
                        },
                        {
                          icon: () => h(NIcon, { component: NotepadEdit20Filled }),
                        }
                      ),
                    default: () => '修改',
                  }),
                  h(NTooltip, null, {
                    trigger: () =>
                      h(
                        NPopconfirm,
                        {
                          onPositiveClick: () => delSong(data),
                        },
                        {
                          trigger: () =>
                            h(
                              NButton,
                              {
                                type: 'error',
                                size: 'small',
                                circle: true,
                              },
                              {
                                icon: () => h(NIcon, { component: Delete24Filled }),
                              }
                            ),
                          default: () => '确认删除该歌曲？',
                        }
                      ),
                    default: () => '删除',
                  }),
                ]
              : null,
          ]
        )
      },
    },
  ]
}
function OnPlayMusic(song: SongsInfo) {
  aplayerMusic.value = undefined
  if (song.from == SongFrom.Netease) GetLyric(song)
  else {
    aplayerMusic.value = {
      title: song.name,
      artist: song.author.join('/') ?? '',
      src: song.url,
      lrc: '',
    }
  }
}
async function GetLyric(song: SongsInfo) {
  QueryGetAPI<{ lyric: string; tlyric: string }>(SONG_API_URL + 'get-netease-lyric', { id: song.id })
    .then((data) => {
      console.log(mergeLyrics(data.data.lyric, data.data.tlyric))
      if (data.code == 200) {
        aplayerMusic.value = {
          title: song.name,
          artist: song.author.join('/') ?? '',
          src: song.url,
          lrc: data.data.tlyric ? mergeLyrics(data.data.lyric, data.data.tlyric) : data.data.lyric,
        }
        //aplayerMusic.value.lrc = data.data.lyric
      }
    })
    .catch((err) => {
      console.error(err)
      aplayerMusic.value = {
        title: song.name,
        artist: song.author.join('/') ?? '',
        src: song.url,
        lrc: '',
      }
    })
}
function mergeLyrics(originalLyrics: string, translatedLyrics: string): string {
  const originalLines = originalLyrics.split('\n')
  const translatedLines = translatedLyrics.split('\n')

  let mergedLyrics = ''

  for (let i = 0; i < originalLines.length; i++) {
    const originalLine = originalLines[i]?.trim()
    const originalTimeMatch = originalLine?.match(/\[(\d{2}:\d{2}\.\d{2,3})\]/) // 匹配原歌词的时间字符串

    let mergedLine = originalLine

    if (originalTimeMatch) {
      const originalTime = originalTimeMatch[1]
      const translatedLineIndex = translatedLines.findIndex((line) => line.includes(originalTime))

      if (translatedLineIndex !== -1) {
        const translatedLine = translatedLines[translatedLineIndex]
        const translatedTimeMatch = translatedLine.match(/\[(\d{2}:\d{2}\.\d{2,3})\]/) // 匹配翻译歌词的时间字符串

        if (translatedTimeMatch && translatedTimeMatch[1] === originalTime) {
          const translatedText = translatedLine.slice(translatedTimeMatch[0].length).trim()
          if (translatedText) {
            mergedLine += ` (${translatedText})`
          }
          translatedLines.splice(translatedLineIndex, 1) // 从翻译歌词数组中移除已匹配的行
        }
      }
    }
    if (!mergedLine.match(/^\[(\d{2}:\d{2}\.\d{2,3})\]$/)) {
      //不是空行
      mergedLyrics += `${mergedLine}\n`
    }
  }

  // 将剩余的非空翻译歌词单独放在一行
  for (const translatedLine of translatedLines) {
    const translatedText = translatedLine.trim()
    if (translatedText) {
      mergedLyrics += `${translatedText}\n`
    }
  }

  return mergedLyrics.trim()
}
function GetPlayButton(song: SongsInfo) {
  switch (song.from) {
    case SongFrom.FiveSing: {
      return h(NTooltip, null, {
        trigger: () =>
          h(
            h(
              NButton,
              {
                size: 'small',
                color: '#00BBB3',
                ghost: true,
                onClick: () => {
                  window.open(`http://5sing.kugou.com/bz/${song.id}.html`)
                },
              },
              {
                icon: () => h(FiveSingIcon, { class: 'svg-icon fivesing' }),
              }
            )
          ),
        default: () => '在5sing打开',
      })
    }
    case SongFrom.Netease:
      return h(NTooltip, null, {
        trigger: () =>
          h(
            NButton,
            {
              size: 'small',
              color: '#C20C0C',
              ghost: true,
              onClick: () => {
                window.open(`https://music.163.com/#/song?id=${song.id}`)
              },
            },
            {
              icon: () => h(NeteaseIcon, { class: 'svg-icon netease' }),
            }
          ),
        default: () => '在网易云打开',
      })
    case SongFrom.Custom:
      return song.url
        ? h(NTooltip, null, {
            trigger: () =>
              h(
                NButton,
                {
                  size: 'small',
                  color: '#6b95bd',
                  ghost: true,
                  onClick: () => {
                    window.open(song.url)
                  },
                },
                {
                  icon: () => h(NIcon, { component: SquareArrowForward24Filled }),
                }
              ),
            default: () => '打开链接',
          })
        : null
  }
}
function renderCell(value: string | number) {
  if (!value) {
    return h(NText, { depth: 3 }, { default: () => '未填写' })
  }
  return value
}

async function updateSong() {
  await QueryPostAPI<SongsInfo>(SONG_API_URL + 'update', {
    key: updateSongModel.value.key,
    song: updateSongModel.value,
  }).then((data) => {
    if (data.code == 200) {
      const index = songsInternal.value.findIndex((s) => s.key == data.data.key)
      songsInternal.value.splice(index, 1, data.data)
      message.success('已更新歌曲信息')
    } else {
      message.error('未能更新歌曲信息: ' + data.message)
    }
  })
}
async function delSong(song: SongsInfo) {
  await QueryGetAPI<SongsInfo>(SONG_API_URL + 'del', {
    key: song.key,
  }).then((data) => {
    if (data.code == 200) {
      songsInternal.value = songsInternal.value.filter((s) => s.key != song.key)
      message.success('已删除歌曲')
    } else {
      message.error('未能删除歌曲: ' + data.message)
    }
  })
}

onMounted(() => {
  songsInternal.value = props.songs
  setTimeout(() => {
    columns.value = createColumns()
  }, 1)
})
</script>

<template>
  <NCard embedded size="small">
    <NSpace>
      <NInput placeholder="搜索歌曲" v-model:value="searchMusicKeyword" size="small" style="width: 150px" />
      <NSelect placeholder="选择歌手" v-model:value="authorColumn.filterOptionValue" :options="authorsOptions" clearable filterable size="small" style="width: 150px" />
      <NButton v-if="authorColumn.filterOptionValue" type="error" @click="authorColumn.filterOptionValue = null" size="small"> 清除歌手选择 </NButton>
    </NSpace>
  </NCard>
  <NDivider style="margin: 5px 0 5px 0"> 共 {{ songsComputed.length }} 首 </NDivider>
  <Transition>
    <div v-if="aplayerMusic" class="song-list">
      <APlayer :music="aplayerMusic" autoplay :showLrc="aplayerMusic.lrc != null && aplayerMusic.lrc.length > 0"/>
      <NDivider style="margin: 15px 0 15px 0" />
    </div>
  </Transition>
  <NDataTable
    size="small"
    :columns="columns"
    :data="songsComputed"
    :pagination="{ itemCount: songsInternal.length, defaultPageSize: 25, pageSizes: [25, 50, 200], size: 'small', showSizePicker: true }"
  />
  <NModal v-model:show="showModal" style="max-width: 600px" preset="card">
    <template #header> 修改信息 </template>
    <NForm ref="formRef" :rules="updateSongRules" :model="updateSongModel" :render-cell="renderCell">
      <NFormItem path="name" label="名称">
        <NInput v-model:value="updateSongModel.name" autosize style="min-width: 200px" placeholder="就是歌曲名称" />
      </NFormItem>
      <NFormItem path="author" label="作者">
        <NSelect v-model:value="updateSongModel.author" filterable multiple tag placeholder="输入，按回车确认" :show-arrow="false" :show="false" />
      </NFormItem>
      <NFormItem path="description" label="备注">
        <NInput v-model:value="updateSongModel.description" placeholder="可选" :maxlength="250" show-count autosize style="min-width: 300px" clearable />
      </NFormItem>
      <NFormItem path="language" label="语言">
        <NSelect v-model:value="updateSongModel.language" multiple :options="songSelectOption" placeholder="可选" />
      </NFormItem>
      <NFormItem path="tags" label="标签">
        <NSelect v-model:value="updateSongModel.tags" filterable multiple clearable tag placeholder="可选，按回车确认" :options="tagsSelectOption" />
      </NFormItem>
      <NFormItem path="url" label="链接">
        <NInput v-model:value="updateSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" :disabled="updateSongModel.from != SongFrom.Custom" />
      </NFormItem>
    </NForm>
    <NDivider style="margin: 10px" />
    <NButton @click="updateSong" type="success"> 更新 </NButton>
  </NModal>
</template>

<style>
.netease path:nth-child(2) {
  fill: #c20c0c;
}
.fivesing:first-child {
  fill: #00bbb3;
}
</style>
