<script setup lang="ts">
import { PlusOutlined } from "@ant-design/icons-vue";
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
import { message } from "ant-design-vue";
import type { PromptRuleSimple, ScheduleTask } from "@geo/shared-types";
import { computed, onBeforeUnmount, reactive, ref, watch } from "vue";
import { useI18n } from "vue-i18n";

import PromptRuleModal from "@/components/PromptRuleModal.vue";
import PublishPlatformSelector from "@/components/PublishPlatformSelector.vue";
import { generateApi, promptRulesApi, schedulesApi } from "@/lib/api";
import { formatError } from "@/lib/errors";
import {
  getAllPublishPlatforms,
  parseTargetPlatforms,
  serializeTargetPlatforms,
} from "@/lib/publish-platforms";

const props = defineProps<{
  open: boolean;
  mode: "instant" | "schedule";
  task?: ScheduleTask | null;
}>();

const emit = defineEmits<{
  "update:open": [value: boolean];
}>();

const queryClient = useQueryClient();
const { t } = useI18n();

const promptDrawerOpen = ref(false);
const coverPreviewUrl = ref("");
const coverFileName = ref("");

const form = reactive({
  name: "",
  promptRuleId: undefined as number | undefined,
  platformIds: [] as string[],
  coverEnabled: true,
  enableWebSearch: false,
  generateCount: 1,
  scheduleTime: "08:00:00",
});

const isSchedule = computed(() => props.mode === "schedule");
const allPlatforms = computed(() => getAllPublishPlatforms());

const rulesQuery = useQuery({
  queryKey: ["promptRules", "simple"],
  queryFn: () => promptRulesApi.listSimple(),
});

const promptOptions = computed(() =>
  (rulesQuery.data.value ?? []).map((rule: PromptRuleSimple) => ({
    label: rule.name,
    value: rule.id,
  })),
);

const drawerTitle = computed(() => {
  if (isSchedule.value) {
    return props.task?.id ? t("custom.schedule.editTitle") : t("custom.schedule.createTitle");
  }
  return t("custom.instant.createTitle");
});

const submitText = computed(() => {
  if (isSchedule.value) {
    return props.task?.id ? t("common.save") : t("custom.task.submit");
  }
  return t("custom.task.submit");
});

watch(
  () => props.open,
  (open) => {
    if (open) {
      hydrateForm();
      return;
    }
    resetCoverState();
  },
);

onBeforeUnmount(() => {
  resetCoverState();
});

const createScheduleMutation = useMutation({
  mutationFn: () =>
    schedulesApi.create({
      name: form.name.trim(),
      prompt_rule_id: form.promptRuleId!,
      cron_expr: buildDailyCron(form.scheduleTime),
      target_platform: serializeTargetPlatforms(form.platformIds),
    }),
  onSuccess: async () => {
    message.success(t("custom.messages.scheduleCreated"));
    emit("update:open", false);
    await queryClient.invalidateQueries({ queryKey: ["schedules"] });
  },
  onError: (error) => message.error(formatError(error)),
});

const updateScheduleMutation = useMutation({
  mutationFn: () =>
    schedulesApi.update(props.task!.id, {
      name: form.name.trim(),
      prompt_rule_id: form.promptRuleId!,
      cron_expr: buildDailyCron(form.scheduleTime),
      target_platform: serializeTargetPlatforms(form.platformIds),
    }),
  onSuccess: async () => {
    message.success(t("custom.messages.scheduleUpdated"));
    emit("update:open", false);
    await queryClient.invalidateQueries({ queryKey: ["schedules"] });
  },
  onError: (error) => message.error(formatError(error)),
});

const instantGenerateMutation = useMutation({
  mutationFn: () =>
    generateApi.fromRule({
      prompt_rule_id: form.promptRuleId!,
      target_platform: serializeTargetPlatforms(form.platformIds),
      extra_params: {
        task_name: form.name.trim(),
        generation_mode: "instant",
        enable_web_search: form.enableWebSearch,
        generate_count: form.generateCount,
        target_platforms: form.platformIds,
        cover_file_name: coverFileName.value || null,
      },
    }),
  onSuccess: async () => {
    message.success(t("custom.messages.generateSubmitted"));
    emit("update:open", false);
    await Promise.all([
      queryClient.invalidateQueries({ queryKey: ["articles"] }),
      queryClient.invalidateQueries({ queryKey: ["instantTasks"] }),
    ]);
  },
  onError: (error) => message.error(formatError(error)),
});

const submitLoading = computed(
  () =>
    createScheduleMutation.isPending.value ||
    updateScheduleMutation.isPending.value ||
    instantGenerateMutation.isPending.value,
);

function hydrateForm(): void {
  form.name = props.task?.name ?? "";
  form.promptRuleId = props.task?.prompt_rule_id ?? undefined;
  form.platformIds = parseTargetPlatforms(props.task?.target_platform);
  form.coverEnabled = true;
  form.enableWebSearch = false;
  form.generateCount = 1;
  form.scheduleTime = parseCronToDailyTime(props.task?.cron_expr);
  resetCoverState();
}

function resetCoverState(): void {
  if (coverPreviewUrl.value) {
    URL.revokeObjectURL(coverPreviewUrl.value);
  }
  coverPreviewUrl.value = "";
  coverFileName.value = "";
}

function handleCoverChange(event: Event): void {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0];
  if (!file) {
    return;
  }

  if (coverPreviewUrl.value) {
    URL.revokeObjectURL(coverPreviewUrl.value);
  }

  coverFileName.value = file.name;
  coverPreviewUrl.value = URL.createObjectURL(file);
}

function handlePromptSaved(ruleId: number): void {
  form.promptRuleId = ruleId;
  promptDrawerOpen.value = false;
  void queryClient.invalidateQueries({ queryKey: ["promptRules", "simple"] });
}

function validateForm(): boolean {
  if (!form.name.trim()) {
    message.warning(t("custom.messages.missingTaskName"));
    return false;
  }

  if (!form.promptRuleId) {
    message.warning(t("custom.messages.missingPromptRule"));
    return false;
  }

  if (form.generateCount < 1) {
    message.warning(t("custom.messages.invalidGenerateCount"));
    return false;
  }

  if (isSchedule.value && !isValidTime(form.scheduleTime)) {
    message.warning(t("custom.messages.invalidScheduleTime"));
    return false;
  }

  return true;
}

async function handleSubmit(): Promise<void> {
  if (!validateForm()) {
    return;
  }

  if (isSchedule.value) {
    if (props.task?.id) {
      await updateScheduleMutation.mutateAsync();
    } else {
      await createScheduleMutation.mutateAsync();
    }
    return;
  }

  await instantGenerateMutation.mutateAsync();
}

function parseCronToDailyTime(cronExpr?: string | null): string {
  if (!cronExpr) {
    return "08:00:00";
  }

  const fiveFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);
  if (fiveFieldMatch) {
    const [, minute, hour] = fiveFieldMatch;
    return `${padTime(hour)}:${padTime(minute)}:00`;
  }

  const sixFieldMatch = cronExpr.match(/^(\d{1,2})\s+(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);
  if (sixFieldMatch) {
    const [, second, minute, hour] = sixFieldMatch;
    return `${padTime(hour)}:${padTime(minute)}:${padTime(second)}`;
  }

  return "08:00:00";
}

function buildDailyCron(timeValue: string): string {
  const [hourRaw, minuteRaw] = timeValue.split(":");
  const hour = Number(hourRaw || 0);
  const minute = Number(minuteRaw || 0);
  return `${minute} ${hour} * * *`;
}

function isValidTime(value: string): boolean {
  return /^\d{2}:\d{2}(:\d{2})?$/.test(value);
}

function padTime(value: string): string {
  return value.padStart(2, "0");
}
</script>

<template>
  <a-drawer
    :open="open"
    :title="drawerTitle"
    placement="right"
    width="1120"
    :mask-closable="false"
    class="generate-task-drawer"
    @close="emit('update:open', false)"
  >
    <div class="generate-task-drawer__body">
      <section class="generate-task-drawer__panel">
        <div class="generate-task-drawer__section-head">
          <div class="generate-task-drawer__section-marker"></div>
          <h3>{{ t("custom.task.basicSection") }}</h3>
        </div>

        <div class="generate-task-drawer__field">
          <label class="generate-task-drawer__label generate-task-drawer__label--required">
            {{ t("custom.task.name") }}：
          </label>
          <a-input
            v-model:value="form.name"
            :maxlength="100"
            size="large"
            :placeholder="t('custom.task.namePlaceholder')"
          />
        </div>

        <div class="generate-task-drawer__field">
          <label class="generate-task-drawer__label generate-task-drawer__label--required">
            {{ t("custom.task.prompt") }}：
          </label>

          <div class="generate-task-drawer__prompt-row">
            <a-select
              v-model:value="form.promptRuleId"
              size="large"
              :placeholder="t('custom.task.promptPlaceholder')"
              :options="promptOptions"
              :loading="rulesQuery.isPending.value"
              allow-clear
              class="generate-task-drawer__prompt-select"
            />

            <a-button class="generate-task-drawer__prompt-create" size="large" @click="promptDrawerOpen = true">
              <template #icon><PlusOutlined /></template>
              {{ t("custom.task.createPrompt") }}
            </a-button>
          </div>
        </div>

        <div class="generate-task-drawer__field">
          <label class="generate-task-drawer__label">{{ t("custom.task.platforms") }}：</label>
          <p class="generate-task-drawer__hint">{{ t("custom.task.platformsHint") }}</p>
          <PublishPlatformSelector v-model="form.platformIds" :platforms="allPlatforms" />
        </div>

        <div class="generate-task-drawer__field">
          <label class="generate-task-drawer__label">{{ t("custom.task.cover") }}：</label>
          <p class="generate-task-drawer__hint">{{ t("custom.task.coverHint") }}</p>

          <label
            class="generate-task-drawer__cover"
            :class="{ 'generate-task-drawer__cover--disabled': !form.coverEnabled }"
          >
            <input
              type="file"
              accept="image/*"
              hidden
              :disabled="!form.coverEnabled"
              @change="handleCoverChange"
            />

            <template v-if="coverPreviewUrl">
              <img :src="coverPreviewUrl" alt="cover preview" />
            </template>
            <template v-else>
              <span class="generate-task-drawer__cover-plus">+</span>
              <strong>{{ t("custom.task.coverUpload") }}</strong>
              <small>{{ coverFileName || t("custom.task.coverUploadHint") }}</small>
            </template>
          </label>
        </div>
      </section>

      <section class="generate-task-drawer__panel generate-task-drawer__panel--bordered">
        <div class="generate-task-drawer__section-head">
          <div class="generate-task-drawer__section-marker"></div>
          <h3>{{ t("custom.task.advancedSection") }}</h3>
        </div>

        <div v-if="isSchedule" class="generate-task-drawer__field">
          <label class="generate-task-drawer__label">{{ t("custom.task.scheduleTime") }}：</label>
          <div class="generate-task-drawer__time-wrapper">
            <span>{{ t("custom.task.scheduleEveryDay") }}</span>
            <a-time-picker
              v-model:value="form.scheduleTime"
              value-format="HH:mm:ss"
              size="large"
              :allow-clear="false"
              style="width: 160px"
            />
          </div>
        </div>

        <div class="generate-task-drawer__field generate-task-drawer__field--inline">
          <label class="generate-task-drawer__label">{{ t("custom.task.enableWebSearch") }}：</label>
          <a-switch v-model:checked="form.enableWebSearch" />
        </div>

        <div class="generate-task-drawer__field generate-task-drawer__field--narrow">
          <label class="generate-task-drawer__label">{{ t("custom.task.generateCount") }}：</label>
          <a-input-number
            v-model:value="form.generateCount"
            :min="1"
            :max="20"
            :precision="0"
            size="large"
          />
        </div>
      </section>
    </div>

    <template #footer>
      <div class="generate-task-drawer__footer">
        <a-button size="large" @click="emit('update:open', false)">
          {{ t("common.cancel") }}
        </a-button>
        <a-button type="primary" size="large" :loading="submitLoading" @click="handleSubmit">
          {{ submitText }}
        </a-button>
      </div>
    </template>

    <PromptRuleModal v-model:open="promptDrawerOpen" @saved="handlePromptSaved" />
  </a-drawer>
</template>

<style scoped>
.generate-task-drawer :deep(.ant-drawer-header) {
  padding: 30px 28px;
  border-bottom: 1px solid #edf2f7;
}

.generate-task-drawer :deep(.ant-drawer-title) {
  color: #111827;
  font-size: 18px;
  font-weight: 800;
}

.generate-task-drawer :deep(.ant-drawer-body) {
  padding: 30px 32px 32px;
  background: #fff;
}

.generate-task-drawer :deep(.ant-drawer-footer) {
  padding: 18px 24px;
  border-top: 1px solid #edf2f7;
  background: #fff;
}

.generate-task-drawer__body {
   padding: 0 20px;
  display: flex;
  flex-direction: column;
}

.generate-task-drawer__panel {
  padding: 16px 0 32px;
}

.generate-task-drawer__panel--bordered {
  padding-top: 32px;
  border-top: 1px solid #edf2f7;
}

.generate-task-drawer__section-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 20px;
  border-bottom: 1px solid #fafafa;
}

.generate-task-drawer__section-marker {
  width: 4px;
  height: 16px;
  border-radius: 2px;
  background: #111827;
}

.generate-task-drawer__section-head h3 {
  margin: 0;
  color: #111827;
  font-size: 16px;
  font-weight: 800;
}

.generate-task-drawer__field {
  margin-top: 24px;
}

.generate-task-drawer__field--inline {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.generate-task-drawer__field--narrow {
  max-width: 220px;
}

.generate-task-drawer__label {
  display: inline-flex;
  align-items: center;
  margin-bottom: 12px;
  color: #1f2937;
  font-size: 15px;
  font-weight: 700;
}

.generate-task-drawer__label--required::before {
  content: "*";
  margin-right: 4px;
  color: #ff4d4f;
}

.generate-task-drawer__hint {
  margin: -2px 0 14px;
  color: #667085;
  font-size: 13px;
  line-height: 1.7;
}

.generate-task-drawer__hint--compact {
  margin-top: 6px;
}

.generate-task-drawer__prompt-row {
  display: flex;
  gap: 12px;
  align-items: center;
}

.generate-task-drawer__prompt-select {
  flex: 0 1 320px;
}

.generate-task-drawer__prompt-create {
  border-style: dashed;
  border-color: #9db7ff;
  color: #355dff;
}

.generate-task-drawer__cover {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 228px;
  min-height: 172px;
  border: 1px dashed #cfd9e8;
  border-radius: 20px;
  background:
    radial-gradient(circle at top, rgba(53, 93, 255, 0.08), transparent 48%),
    #fbfcff;
  color: #1f2937;
  cursor: pointer;
  overflow: hidden;
}

.generate-task-drawer__cover img {
  width: 100%;
  height: 172px;
  object-fit: cover;
}

.generate-task-drawer__cover strong {
  font-size: 16px;
  font-weight: 700;
}

.generate-task-drawer__cover small {
  color: #667085;
  font-size: 13px;
}

.generate-task-drawer__cover--disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.generate-task-drawer__cover-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: #eef4ff;
  color: #355dff;
  font-size: 28px;
  line-height: 1;
}

.generate-task-drawer__time-wrapper {
  display: flex;
  align-items: center;
  gap: 12px;
}

.generate-task-drawer__time-wrapper span {
  color: #344054;
  font-size: 15px;
  font-weight: 600;
}

.generate-task-drawer__footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

@media (max-width: 1024px) {
  .generate-task-drawer__prompt-row {
    flex-direction: column;
    align-items: stretch;
  }

  .generate-task-drawer__prompt-select {
    flex-basis: auto;
  }
}
</style>
