<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, NTag } 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'
import { useAuthStore } from '@/stores/auth'

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

const showSettingsModal = 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 = ''
  showSettingsModal.value = false
}

async function addGame(name: string, id: number) {
  const now = new Date().toISOString()
  const resAddGame = await client.AddGame({
    name: ('Тестовая игра: ' + name).trim(),
    description: 'Тестовая игра',
    startAt: now,
    scenarioId: id
  })
  if (resAddGame.error != '') {
    message.error(resAddGame.error!)
    return
  }
  const resAddTeam = await client.AddTeam({
    name: 'Тестовая команда',
    gameId: resAddGame.id!,
  })
  if (resAddTeam.error != '') {
    message.error(resAddTeam.error!)
    return
  }
  router.push("/team-story/" + resAddTeam.id! + '?password=' + resAddTeam.password!)
}

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 = ''
  showSettingsModal.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))
  showSettingsModal.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))
}

function getRandomComplimentForNastya() {
  const compliments = [
    { text: 'Настя, ты просто ослепительна сегодня!', nameForm: 'Настя' },
    { text: 'У Насти невероятный вкус!', nameForm: 'Насти' },
    { text: 'Настенька, твоя улыбка делает мир ярче.', nameForm: 'Настенька' },
    { text: 'С Настей всегда интересно общаться.', nameForm: 'Настей' },
    { text: 'Настя, ты — источник вдохновения для всех вокруг.', nameForm: 'Настя' },
    { text: 'Мне нравится, как Настя смотрит на мир.', nameForm: 'Настя' },
    { text: 'Настюха, ты супер!', nameForm: 'Настюха' },
    { text: 'Талант Насти поражает!', nameForm: 'Насти' },
    { text: 'Настя, твоя энергия заряжает батарейки!', nameForm: 'Настя' },
    { text: 'С Настей хочется проводить каждую минуту.', nameForm: 'Настей' },
    { text: 'Настенька, ты — самое красивое, что случилось в этом мире.', nameForm: 'Настенька' },
    { text: 'У Насти золотое сердце.', nameForm: 'Насти' }
  ];

  const randomIndex = Math.floor(Math.random() * compliments.length);
  return compliments[randomIndex].text;
}
</script>

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

        <n-alert v-if="authStore.user?.id == 2" :title="getRandomComplimentForNastya()" type="info"
          style="margin-bottom: 20px;"></n-alert>

        <div class="settings-block">
          Точек: {{ scenario.story?.places?.length }}
          <n-button quaternary @click="showSettingsModal = 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.oldCode">
          <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)" :disabled="place.code == ''">Сохранить</n-button>
          </n-flex>
        </PlaceBlock>
      </div>
    </div>
  </div>

  <!-- Окно настроек -->
  <n-modal v-model:show="showSettingsModal">
    <n-card style="width: 600px" title="Настройки сценария" :bordered="false" size="huge" role="dialog"
      aria-modal="true">
      <template #header-extra>
        <n-button @click="showSettingsModal = 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>
        <n-button @click="addGame(scenario.name || '', scenario.id!)" ghost>
          Создать игру
        </n-button>

        <hr class="settings-hr" />
        <p>Публикация</p>
        <p>
          <n-tag v-if="scenario.status == 'public'" :bordered="false" type="success" class="status-block">
            Опубликовано
          </n-tag>
          <n-tag v-if="scenario.status == 'draft'" :bordered="false" type="warning" class="status-block">
            В разработке
          </n-tag>
        </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 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;
}
</style>
