<script setup lang="ts">
import { Settings } from '@vicons/carbon'
import { Icon } from '@vicons/utils'
import { NButton, type UploadFileInfo, useMessage } from 'naive-ui'
import { NCard, NFlex, NInput, NModal, NSpace, NText, NUpload, NUploadDragger, NAlert } from 'naive-ui'
import { ref } from 'vue'
import { useRoute } from 'vue-router'

import { getAuthClient } from '@/api/auth_client'
import type { Place, Scenario } from '@/api/generated/crabs/evening_detective_server'
import HeaderMenu from '@/components/HeaderMenu.vue'
import PlaceBlock from '@/components/PlaceBlock.vue'
import router from '@/router'

const client = getAuthClient()
const route = useRoute()
const scenarioId = route.params.id

const showSettingsScenarioModal = ref(false)
const statusScenarioName = ref('')
const deletedScenarioName = ref('')

const message = useMessage()

const fileList = ref<UploadFileInfo[]>([])

const scenario = ref<Scenario>({
  id: undefined,
  name: undefined,
  story: undefined,
  author: undefined,
  status: undefined,
  updatedAt: undefined,
  createdAt: undefined,
  publishedAt: undefined,
})

async function getScenario(id: number) {
  const res = await client.GetFullScenario({ id: id })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  scenario.value = res.scenario!
  scenario.value.story?.places?.forEach((item) => {
    item.oldCode = item.code
    item.mode = 'show-editor'
  })
}
getScenario(Number(scenarioId))

async function deleteScenario(id: number) {
  const res = await client.DeleteScenario({ id: id })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  router.push('/scenarios')
}

async function publicScenario(id: number) {
  const res = await client.PublicScenario({ id: id })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))
  statusScenarioName.value = ''
  showSettingsScenarioModal.value = false
}



async function draftScenario(id: number) {
  const res = await client.DraftScenario({ id: id })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))
  statusScenarioName.value = ''
  showSettingsScenarioModal.value = false
}

async function uploadFile(file: File | null, filename: string): Promise<string> {
  if (!file) {
    return ''
  }

  // Читаем как ArrayBuffer
  const arrayBuffer = await file.arrayBuffer()
  const bytes = new Uint8Array(arrayBuffer)

  const resUploadFile = await client.UploadFile({
    filename: filename,
    data: uint8ToBase64(bytes),
  })
  if (resUploadFile.error != '') {
    message.error(resUploadFile.error!)
    return ''
  }

  return resUploadFile.filename || ''
}

async function updateScenario() {
  let resUploadFilename = ''
  if (fileList.value && fileList.value.length > 0) {
    const file = fileList.value[0].file || null
    if (file == null) {
      return
    }
    resUploadFilename = await uploadFile(file, 'scenarios_' + scenario.value.id + '_' + file.name)
    if (resUploadFilename === '') {
      return
    }
  }

  const res = await client.UpdateScenario({
    id: scenario.value.id,
    name: scenario.value.name,
    description: scenario.value.description,
    image: resUploadFilename,
  })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))
  showSettingsScenarioModal.value = false
}

function uint8ToBase64(uint8Array: Uint8Array) {
  // Преобразуем Uint8Array в двоичную строку
  const binaryString = String.fromCharCode(...uint8Array)
  // Кодируем в Base64
  return btoa(binaryString)
}

const code = ref('')
const name = ref('')
const text = ref('')
const mode = ref('mini-add')


async function addPlace() {
  const res = await client.AddScenarioPlace({
    id: scenario.value.id,
    place: {
      code: code.value,
      name: name.value,
      text: text.value,
      image: undefined,
      hidden: undefined,
      applications: undefined,
      doors: undefined,
      keys: undefined,
    },
  })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))

  code.value = ''
  name.value = ''
  text.value = ''
  mode.value = 'add'
}

async function cancelAddPlace() {
  code.value = ''
  name.value = ''
  text.value = ''
  mode.value = 'mini-add'
}

async function addNotFoundDoors(scenario: Scenario, place: Place) {
  for (const door of place.doors || []) {
    const place = scenario.story?.places?.find((place) => {
      return place.code == door.code
    })
    if (place == undefined) {
      const res = await client.AddScenarioPlace({
        id: scenario.id,
        place: {
          code: door.code,
          name: door.name,
          text: undefined,
          image: undefined,
          hidden: true,
          applications: undefined,
          doors: undefined,
          keys: undefined
        },
      })
      if (res.error != '') {
        message.error(res.error!)
        return
      }
    }
  }
}

async function cancelUpdatePlace(place: Place) {
  await getScenario(Number(scenarioId))

  place.mode = 'show-editor'
}

async function updatePlace(place: Place) {
  if (place.fileList && place.fileList.length > 0) {
    const file = place.fileList[0].file || null
    if (file == null) {
      return
    }
    const resUploadFilename = await uploadFile(file, 'scenarios_' + scenario.value.id + '_place_' + place.code + '_' + file.name)
    if (resUploadFilename === '') {
      return
    }
    place.image = resUploadFilename
  }

  await addNotFoundDoors(scenario.value, place)
  const res = await client.UpdateScenarioPlace({
    id: scenario.value.id,
    code: place.oldCode,
    place: place,
  })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))

  place.mode = 'show-editor'
}

async function deletePlace(place: Place) {
  const res = await client.DeleteScenarioPlace({
    id: scenario.value.id,
    code: place.oldCode,
  })
  if (res.error != '') {
    message.error(res.error!)
    return
  }
  await getScenario(Number(scenarioId))
}
</script>

<template>
  <div class="center-block-custom-big">
    <div class="places-container">
      <n-alert v-if="scenario.status == 'public'" title="Сценарий опубликован" type="warning"
        style="margin-bottom: 20px;">
        Не рекомендуется редактировать сценарий когда он опубликован.
      </n-alert>

      <div class="settings-block">
        Точек: {{ scenario.story?.places?.length }}
        <n-button quaternary @click="showSettingsScenarioModal = true" class="settings-button">
          <Icon class="settings-icon">
            <Settings />
          </Icon>
          Настройки
        </n-button>
      </div>

      <PlaceBlock v-model:mode="mode" v-model:newPlaceCode="code" v-model:newPlaceName="name"
        v-model:newPlaceText="text">
        <n-flex justify="end">
          <n-button @click="cancelAddPlace()">Отмена</n-button>
          <n-button @click="addPlace()" :disabled="!code">Добавить точку</n-button>
        </n-flex>
      </PlaceBlock>

      <PlaceBlock :place="place" v-model:mode="place.mode" v-for="place in scenario.story?.places"
        v-bind:key="place.code">
        <n-flex justify="end">
          <n-button @click="deletePlace(place)" type="error" ghost>Удалить</n-button>
          <n-button @click="cancelUpdatePlace(place)">Отмена</n-button>
          <n-button @click="updatePlace(place)">Сохранить</n-button>
        </n-flex>
      </PlaceBlock>
    </div>
  </div>

  <!-- Окно настроек сценария -->
  <n-modal v-model:show="showSettingsScenarioModal">
    <n-card style="width: 600px" title="Настройки сценария" :bordered="false" size="huge" role="dialog"
      aria-modal="true">
      <template #header-extra>
        <n-button @click="showSettingsScenarioModal = false"> x </n-button>
      </template>
      <n-space vertical>
        <p>Название</p>
        <n-input v-model:value="scenario.name" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />

        <p class="settings-header">Описание</p>
        <n-input v-model:value="scenario.description" type="textarea" placeholder="Убийство пастуха..." />

        <p class="settings-header">Картинка</p>
        <n-input v-model:value="scenario.image" type="text" placeholder="default_scenario.png" disabled />
        <n-upload directory-dnd :max="1" v-model:file-list="fileList">
          <n-upload-dragger>
            <n-text style="font-size: 16px">
              Щелкните или перетащите файл в эту область для загрузки
            </n-text>
          </n-upload-dragger>
        </n-upload>

        <n-button @click="updateScenario()" ghost> Сохранить изменения </n-button>

        <hr class="settings-hr" />
        <p>Публикация</p>
        <p>Статус:
          <span v-if="scenario.status == 'public'">опубликовано</span>
          <span v-if="scenario.status == 'draft'">в разработке</span>
        </p>
        <p>
          Введите название сценария <n-text class="name-text" strong>{{ scenario.name }}</n-text>
        </p>
        <n-input v-model:value="statusScenarioName" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
        <n-button v-if="scenario.status != 'public'" @click="publicScenario(scenario.id!)" ghost
          :disabled="statusScenarioName != scenario.name">
          Опубликовать сценарий
        </n-button>
        <n-button v-if="scenario.status != 'draft'" @click="draftScenario(scenario.id!)" ghost
          :disabled="statusScenarioName != scenario.name">
          Снять сценарий с публикации
        </n-button>

        <hr class="settings-hr" />

        <p>
          Введите название сценария
          <n-text class="name-text" strong>{{ scenario.name }}</n-text> чтобы удалить его
        </p>
        <n-input v-model:value="deletedScenarioName" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
        <n-button @click="deleteScenario(scenario.id!)" type="error" ghost
          :disabled="deletedScenarioName != scenario.name">
          Удалить сценарий
        </n-button>
      </n-space>
      <template #footer> </template>
    </n-card>
  </n-modal>

  <HeaderMenu :add-logout="true" active="scenarios" />
</template>

<style scoped>
.settings-block {
  height: 40px;

  /* background-color: brown; */
}

.settings-button {
  float: right;
}

.settings-icon {
  width: 20px;
}

.name-text {
  padding: 3px;
  border-radius: 3px;
  background-color: rgb(255 255 255 / 10%);
}

.settings-header {
  margin-top: 20px;
}

.settings-hr {
  margin: 20px 0;
}

.places-container {
  display: flex;
  flex-flow: column nowrap;
  overflow-y: auto;
  margin-top: 70px;
  padding: 20px;
  height: calc(100vh - 150px);

  /* border: 1px solid red; */
}

@media (width >=1024px) {
  .places-container {
    padding: 20px 250px;
    height: calc(100vh - 70px);
  }
}
</style>
