<template>
  <div class="message-container">
    <div v-if="hasCustomers">
        <Row :gutter="24">
          <Col
            :span="16"
            :offset="4"
          >
            <Alert
              v-if="isRunLimitVisible"
              type="warning"
              show-icon
              class="mb-20"
            >
              {{ $t('FEATURE_RUN_LIMIT_INFO', { limit: autoRunLimit }) }}
            </Alert>

            <Card
              dis-hover
              class="mb-20"
            >
              <div slot="title">
                <Icon
                  type="ios-stats"
                  size="18"
                />
                <span class="ml-5">{{ $t('SEND_MESSAGE_STAT_OVERVIEW') }}</span>
              </div>
              <Row :gutter="16">
                <Col
                  v-for="(stat, index) in overviewStats"
                  :key="stat.key"
                  :span="4"
                  :offset="index === 0 ? 2 : 0"
                >
                  <div class="stat-item">
                    <div class="stat-label">
                      {{ stat.label }}
                    </div>
                    <div
                      class="stat-value"
                      :class="stat.valueClass"
                    >
                      {{ stat.value }}
                    </div>
                  </div>
                </Col>
              </Row>
              <div class="mt-10">
                <div class="config-label compact">
                  {{ $t('SEND_MESSAGE_SENT_PERCENT', { percent: sendProgressPercent }) }}
                </div>
                <Progress
                  :percent="sendProgressPercent"
                  :status="sendProgressPercent >= 100 ? 'success' : 'active'"
                  :stroke-width="12"
                  :stroke-color="sendProgressPercent >= 100 ? '#19be6b' : '#2d8cf0'"
                  hide-info
                />
              </div>
            </Card>

            <Card
              dis-hover
              class="mb-20"
            >
              <div slot="title">
                <Icon
                  type="ios-chatbubbles"
                  size="18"
                />
                <span class="ml-5">{{ $t('SEND_MESSAGE_CONTENT_LABEL') }}</span>
              </div>
              <div class="content-scroll-container">
                <ContentBlock
                  v-model="listContent"
                  :disabled="sending"
                />
              </div>
            </Card>

            <Card
              dis-hover
              class="mb-20"
            >
              <div slot="title">
                <Icon
                  type="ios-settings"
                  size="18"
                />
                <span class="ml-5">{{ $t('SEND_MESSAGE_CONFIG_TITLE') }}</span>
              </div>
              <Row :gutter="16">
                <Col
                  v-for="field in configInputFields"
                  :key="field.key"
                  :span="field.span"
                >
                  <div>
                    <div class="config-label">
                      {{ field.label }}
                    </div>
                    <InputNumber
                      v-model="configSend[field.key]"
                      :min="field.min"
                      :disabled="sending"
                      style="width: 100%"
                    />
                  </div>
                </Col>
                <Col :span="24">
                  <Alert
                    class="mt-20"
                    :message="sendMessageConfigToolTip"
                    type="info"
                  >
                    {{ sendMessageConfigToolTip }}
                  </Alert>
                </Col>
              </Row>
            </Card>

            <div class="action-toolbar mb-20">
              <div class="action-toolbar__config">
                <span class="config-label compact">
                  {{ $t('SEND_MESSAGE_MAX_SEND_COUNT') }}
                </span>
                <InputNumber
                  v-model="configSend.maxSendCount"
                  v-tooltip="$t('SEND_MESSAGE_MAX_SEND_COUNT_TOOL_TIP')"
                  :min="0"
                  :disabled="sending"
                  style="width: 80px"
                />
              </div>
              <div class="action-toolbar__buttons">
                <Button
                  class="mr-10"
                  :loading="savingConfig"
                  :disabled="sending"
                  @click="saveConfig"
                >
                  {{ $t('SAVE_BTN') }}
                </Button>
                <Button
                  type="primary"
                  class="mr-10"
                  :loading="sending"
                  :disabled="!canStartSending"
                  @click="startSending"
                >
                  {{ $t('SEND_MESSAGE_START_BTN') }}
                </Button>
                <Button
                  v-if="hasSkippedCustomers"
                  type="warning"
                  class="mr-10"
                  :loading="resendingSkipped"
                  :disabled="sending"
                  @click="resendSkippedCustomers"
                >
                  {{ $t('SEND_MESSAGE_RESEND_SKIPPED_BTN') }}
                </Button>
                <Button
                  v-if="sending"
                  type="error"
                  @click="stopSending"
                >
                  {{ $t('SEND_MESSAGE_STOP_BTN') }}
                </Button>
              </div>
            </div>

            <Card
              dis-hover
              class="mb-20"
            >
              <div slot="title">
                <Icon
                  type="ios-list"
                  size="18"
                />
                <span class="ml-5">{{ $t('SEND_MESSAGE_LOG_SENDING') }}</span>
              </div>
              <div class="log-container">
                <div
                  v-if="!log.length"
                  class="empty-log"
                >
                  <Icon
                    type="ios-chatbubbles"
                    size="48"
                    class="empty-icon"
                  />
                  <p class="empty-text">
                    {{ $t('SEND_MESSAGE_LOG_EMPTY') }}
                  </p>
                </div>
                <template v-else>
                  <div
                    v-for="(item, index) in log"
                    :key="index"
                    class="log-item"
                    :class="`log-${item.type}`"
                  >
                    <Icon
                      :type="getLogIconType(item.type)"
                      :class="`text-${getLogColorType(item.type)}`"
                      size="16"
                    />
                    <span class="ml-5"> {{ formatDate(item.time) }} - {{ item.message }} </span>
                  </div>
                </template>
              </div>
            </Card>

            <Card dis-hover>
              <div slot="title">
                <Icon
                  type="ios-people"
                  size="18"
                />
                <span class="ml-5">{{ $t('SEND_MESSAGE_CUSTOMER_LIST_TITLE') }}</span>
              </div>
              <div>
                <Table
                  :loading="loadingCustomer"
                  :columns="tableColumns"
                  :data="listCustomer"
                  border
                  size="small"
                  highlight-row
                >
                  <template
                    slot="index"
                    slot-scope="{ index }"
                  >
                    {{ (paggingCustomer.current - 1) * paggingCustomer.limit + index + 1 }}
                  </template>
                  <template
                    slot="status"
                    slot-scope="{ row }"
                  >
                    <Tag :color="getCustomerStatusColor(row.status)">
                      {{ $t(`MARKETING_SENDER_CUSTOMER_STATUS.${row.status}`) }}
                    </Tag>
                  </template>
                  <template
                    slot="sentAt"
                    slot-scope="{ row }"
                  >
                    {{ formatDate(row.sentAt) }}
                  </template>
                </Table>
                <div class="mt-10 text-right">
                  <Page
                    v-model="paggingCustomer.current"
                    :total="paggingCustomer.total"
                    :page-size="paggingCustomer.limit"
                    show-sizer
                    show-total
                    :page-size-opts="paggingCustomer.size"
                    @on-change="onPaggingCustomerChange"
                    @on-page-size-change="onPaggingCustomerSize"
                  />
                </div>
              </div>
            </Card>
          </Col>
        </Row>
      </div>
      <div
        v-else
        class="empty-customer-container"
      >
        <Icon
          type="ios-contacts"
          size="64"
          class="empty-customer-icon"
        />
        <p class="empty-customer-title">
          {{ $t('SEND_MESSAGE_CUSTOMER_LIST_EMPTY') }}
        </p>
        <p class="empty-customer-desc">
          {{ $t('SEND_MESSAGE_NO_CUSTOMER_READY') }}
        </p>
        <Button
          type="primary"
          class="mt-20"
          icon="ios-search"
          @click="openPopupUrl(collectCustomerUrl)"
        >
          {{ $t('SEND_MESSAGE_FETCH_CUSTOMER_BTN') }}
        </Button>
      </div>
  </div>
</template>
<script>
import {
  sendChatMessage,
  setConversationClosed,
  setConversationActive,
  getConversationRedirection,
} from '@/api/shopee/seller/chat';
import { getShopeeShopByUsername } from '@/api/shopee/client/shop';
import { KVShopeeMarketingSenderCustomer } from '@/plugins/kv';
import ContentBlock from '@/vue/components/Shopee/Seller/SendMessage/ContentBlock.vue';
import {
  ShopeeMarketingSenderCollect,
  ShopeeMarketingSenderCustomer,
  getDefaultMarketingSenderConfig,
  getDefaultMarketingSenderContent,
} from '@/models/shopee/marketing/sender';
import { SHOPEE_AUTO_RUN_LIMITS } from '@/constant/shopee';

const CONFIG_SEND = {
  delayPerContent: 1000,
};

export default {
  name: 'ShopeeAutoSendMessageSend',
  components: {
    ContentBlock,
  },
  data() {
    return {
      collectId: this.$route.params.id,
      collectData: {
        totalCustomers: 0,
        sentCount: 0,
        failedCount: 0,
        skippedCount: 0,
        status: 'pending',
      },
      configSend: getDefaultMarketingSenderConfig(),
      listContent: getDefaultMarketingSenderContent(),
      loadingCustomer: false,
      savingConfig: false,
      resendingSkipped: false,
      paggingCustomer: {
        current: 1,
        limit: 20,
        total: 0,
        size: [10, 20, 50, 100],
      },
      listCustomer: [],
      sending: false,
      stopRequested: false,
      log: [],
    };
  },
  computed: {
    hasCustomers() {
      return Number(this.collectData.totalCustomers || 0) > 0;
    },
    collectCustomerUrl() {
      if (!this.collectId) {
        return '';
      }
      return `/shopee/seller/auto/send-message/collect/${this.collectId}`;
    },
    sendMessageConfigToolTip() {
      return this.$t('SEND_MESSAGE_CONFIG_TOOL_TIP', {
        sleep: this.configSend.delayBetweenSeconds,
        count: this.configSend.pauseAfterCount,
        wait: this.configSend.pauseDurationSeconds,
        skip: this.configSend.duplicateCooldownMinutes,
      });
    },
    overviewStats() {
      return [
        {
          key: 'total',
          label: this.$t('MARKETING_SENDER_COLUMN_TOTAL_CUSTOMERS'),
          value: this.collectData.totalCustomers || 0,
          valueClass: '',
        },
        {
          key: 'sent',
          label: this.$t('MARKETING_SENDER_COLUMN_SENT_COUNT'),
          value: this.collectData.sentCount || 0,
          valueClass: 'text-success',
        },
        {
          key: 'skipped',
          label: this.$t('MARKETING_SENDER_COLUMN_SKIPPED_COUNT'),
          value: this.skippedCustomers,
          valueClass: 'text-warning',
        },
        {
          key: 'failed',
          label: this.$t('MARKETING_SENDER_COLUMN_FAILED_COUNT'),
          value: this.collectData.failedCount || 0,
          valueClass: 'text-error',
        },
        {
          key: 'pending',
          label: this.$t('SEND_MESSAGE_STAT_PENDING'),
          value: this.pendingCustomers,
          valueClass: 'text-warning',
        },
      ];
    },
    configInputFields() {
      return [
        {
          key: 'delayBetweenSeconds',
          label: this.$t('SEND_MESSAGE_DELAY_BETWEEN'),
          min: 0,
          span: 6,
        },
        {
          key: 'pauseAfterCount',
          label: this.$t('SEND_MESSAGE_PAUSE_AFTER_COUNT'),
          min: 1,
          span: 6,
        },
        {
          key: 'pauseDurationSeconds',
          label: this.$t('SEND_MESSAGE_PAUSE_DURATION', {
            count: this.configSend.pauseAfterCount,
          }),
          min: 0,
          span: 6,
        },
        {
          key: 'duplicateCooldownMinutes',
          label: this.$t('SEND_MESSAGE_DUPLICATE_COOLDOWN'),
          min: 0,
          span: 6,
        },
      ];
    },
    skippedCustomers() {
      return Number(this.collectData.skippedCount) || 0;
    },
    pendingCustomers() {
      const total = Number(this.collectData.totalCustomers) || 0;
      const sent = Number(this.collectData.sentCount) || 0;
      const failed = Number(this.collectData.failedCount) || 0;
      const skipped = Number(this.collectData.skippedCount) || 0;
      const pending = total - sent - failed - skipped;
      if (pending > 0) {
        return pending;
      }
      return 0;
    },
    sendProgressPercent() {
      const total = Number(this.collectData.totalCustomers) || 0;
      const sent = total - (Number(this.pendingCustomers) || 0);

      if (total <= 0 || sent <= 0) {
        return 0;
      }
      const percent = Math.round((sent / total) * 100);
      if (percent < 0) {
        return 0;
      }
      if (percent > 100) {
        return 100;
      }
      return percent;
    },
    autoRunLimit() {
      const config = SHOPEE_AUTO_RUN_LIMITS.sendMessage[this.getUserPlan];
      if (config) {
        return config.runLimit;
      }
      return 0;
    },
    isRunLimitVisible() {
      return Number.isFinite(this.autoRunLimit) && this.autoRunLimit > 0;
    },
    isRunLimitReached() {
      return this.isRunLimitVisible && this.collectData.sentCount >= this.autoRunLimit;
    },
    canStartSending() {
      if (
        this.sending
          || this.isRunLimitReached
          || !this.listContent
          || !this.listContent.length
          || !this.collectData.totalCustomers
      ) {
        return false;
      }

      return !!this.normalizeListContent(this.listContent).length;
    },
    hasSkippedCustomers() {
      return this.listCustomer.some((customer) => customer.status === 'skipped');
    },
    tableColumns() {
      return [
        {
          title: '#',
          slot: 'index',
          width: 60,
          align: 'center',
        },
        {
          title: this.$t('ORDER_BUYER_NAME'),
          key: 'customerName',
          minWidth: 160,
        },
        {
          title: 'User ID',
          key: 'toUserId',
          width: 120,
        },
        {
          title: this.$t('MARKETING_SENDER_COLUMN_STATUS'),
          slot: 'status',
          width: 130,
          align: 'center',
        },
        {
          title: this.$t('SEND_MESSAGE_TABLE_SENT_AT'),
          slot: 'sentAt',
          width: 170,
        },
        {
          title: this.$t('SEND_MESSAGE_CONTENT_LABEL'),
          key: 'message',
          minWidth: 220,
        },
        {
          title: this.$t('RESULT_LOG'),
          key: 'error',
          minWidth: 220,
        },
      ];
    },
  },
  methods: {
    async createdHook() {
      await this.fetchCollect();
      await this.fetchCustomers();
    },
    async fetchCollect() {
      try {
        const collect = await ShopeeMarketingSenderCollect.getId(this.collectId);

        if (!collect) {
          this.$Message.error(this.$t('ERROR_GET_DATA'));
          return;
        }

        this.collectData = {
          totalCustomers: collect.totalCustomers || 0,
          sentCount: collect.sentCount || 0,
          failedCount: collect.failedCount || 0,
          skippedCount: collect.skippedCount || 0,
          status: collect.status || 'pending',
        };

        // Fetch skipped count from database
        await this.fetchSkippedCount();
        this.paggingCustomer.total = this.collectData.totalCustomers;
        this.configSend = {
          ...getDefaultMarketingSenderConfig(),
          ...(collect.configSend || {}),
        };

        this.listContent = collect.listContent && collect.listContent.length
          ? collect.listContent
          : getDefaultMarketingSenderContent();
      } catch (error) {
        this.$Message.error(this.$t('ERROR_GET_DATA'));
        this.loggerApi.error('Fetch collect error:', error);
      }
    },
    async fetchCustomers() {
      this.loadingCustomer = true;
      try {
        const skip = (this.paggingCustomer.current - 1) * this.paggingCustomer.limit;

        const where = {
          collectId: this.collectId,
        };

        const listCustomer = await ShopeeMarketingSenderCustomer.findMany(
          where,
          this.paggingCustomer.limit,
          skip,
        );

        listCustomer.sort((a, b) => {
          const timeA = a.updatedAt || 0;
          const timeB = b.updatedAt || 0;
          return timeB - timeA;
        });

        this.listCustomer = listCustomer;

        const actualCount = await ShopeeMarketingSenderCustomer.count(where);

        if (actualCount !== this.collectData.totalCustomers) {
          this.collectData.totalCustomers = actualCount;
          await ShopeeMarketingSenderCollect.updateId(
            this.collectId,
            {
              totalCustomers: actualCount,
            },
            false,
          );
        }
        this.paggingCustomer.total = actualCount;

        // Update skipped count
        await this.fetchSkippedCount();
      } catch (error) {
        this.$Message.error(this.$t('ERROR_GET_DATA'));
        this.loggerApi.error('Fetch customers error:', error);
      } finally {
        this.loadingCustomer = false;
      }
    },
    async fetchSkippedCount() {
      try {
        const where = {
          collectId: this.collectId,
          status: 'skipped',
        };
        const skippedCount = await ShopeeMarketingSenderCustomer.count(where);
        this.collectData.skippedCount = skippedCount || 0;
      } catch (error) {
        this.loggerApi.error('Fetch skipped count error:', error);
      }
    },
    onPaggingCustomerChange(page) {
      this.paggingCustomer.current = page;
      this.fetchCustomers();
    },
    onPaggingCustomerSize(limit) {
      this.paggingCustomer.limit = limit;
      this.paggingCustomer.current = 1;
      this.fetchCustomers();
    },
    async saveConfig() {
      this.savingConfig = true;
      try {
        const payload = {
          configSend: this.normalizeConfig(this.configSend),
          listContent: this.normalizeListContent(this.listContent),
        };
        await ShopeeMarketingSenderCollect.updateId(this.collectId, payload, false);
        this.$Message.success(this.$t('SAVE_SUCCESS'));
      } catch (error) {
        this.$Message.error(this.$t('SAVE_ERROR'));
        this.loggerApi.error('Save config error:', error);
      } finally {
        this.savingConfig = false;
      }
    },
    normalizeConfig(config) {
      return {
        delayBetweenSeconds: Number(config.delayBetweenSeconds || 0),
        pauseAfterCount: Number(config.pauseAfterCount || 1),
        pauseDurationSeconds: Number(config.pauseDurationSeconds || 0),
        duplicateCooldownMinutes: Number(config.duplicateCooldownMinutes || 0),
        maxSendCount: Number(config.maxSendCount || 0),
      };
    },
    normalizeListContent(listContent) {
      if (!listContent || !Array.isArray(listContent)) {
        return getDefaultMarketingSenderContent();
      }

      return listContent
        .filter((item) => item && item.type)
        .filter((item) => {
          return (
            (item.type === 'text' && item.text && item.text.trim())
              || (item.type === 'sticker' && item.payload && item.payload.stickerId)
              || (item.type === 'image' && item.payload && item.payload.imageId)
              || (item.type === 'product' && item.payload && item.payload.productId)
              || (item.type === 'voucher' && item.payload && item.payload.voucherId)
          );
        });
    },
    stopSending() {
      if (!this.sending) {
        return;
      }
      this.stopRequested = true;
      this.addLog('warning', this.$t('SEND_MESSAGE_STOPPING'));
    },
    async startSending() {
      if (this.sending) {
        return;
      }

      const normalizedContent = this.normalizeListContent(this.listContent);

      const isHasValidContent = normalizedContent.length;

      if (!isHasValidContent) {
        this.$Message.error(this.$t('SEND_MESSAGE_CONTENT_REQUIRED'));
        return;
      }

      const queue = await this.getQueueCustomers();

      if (!queue.length) {
        this.$Message.info(this.$t('SEND_MESSAGE_NO_CUSTOMER_READY'));
        return;
      }

      const maxSendCount = this.getMaxSendCount();

      this.sending = true;

      this.stopRequested = false;

      this.log = [];

      await this.saveConfigSilently();

      await this.updateCollectStatus('sending');

      try {
        const { reachedMax } = await this.processQueue(queue, normalizedContent, maxSendCount);
        if (this.stopRequested) {
          await this.updateCollectStatus('pending');
          this.addLog('warning', this.$t('SEND_MESSAGE_STOPPED'));
        } else if (reachedMax) {
          await this.updateCollectStatus('pending');
        } else {
          await this.updateCollectStatus('completed');
          this.$Message.success(this.$t('SEND_MESSAGE_DONE'));
        }
      } catch (error) {
        await this.updateCollectStatus('failed');
        this.addLog('error', error?.message || error?.toString() || 'ERROR');
        this.$Message.error(this.$t('SEND_MESSAGE_UNEXPECTED_ERROR'));
      } finally {
        this.sending = false;
        this.stopRequested = false;
        await this.fetchCollect();
        await this.fetchCustomers();
      }
    },
    async processQueue(queue, normalizedContent, maxSendCount) {
      let sentSincePause = 0;
      let totalSent = 0;
      let reachedMax = false;
      const hasMaxLimit = maxSendCount !== Number.MAX_SAFE_INTEGER;

      for (let index = 0; index < queue.length; index += 1) {
        if (this.stopRequested) {
          break;
        }

        const customer = queue[index];
        await this.handleCustomerSending(customer, normalizedContent);

        sentSincePause += 1;
        totalSent += 1;

        if (hasMaxLimit && totalSent >= maxSendCount) {
          reachedMax = true;
          this.addLog('warning', this.$t('SEND_MESSAGE_LOG_REACHED_MAX', { count: maxSendCount }));
          break;
        }

        if (totalSent >= this.autoRunLimit) {
          reachedMax = true;
          const msg = this.$t('FEATURE_RUN_LIMIT_REACHED', {
            sent: totalSent,
            limit: this.autoRunLimit,
          });
          this.$Message.warning(msg);
          this.addLog('warning', msg);
          break;
        }

        sentSincePause = await this.handleDelayAfterCustomer(sentSincePause);
      }

      return { reachedMax };
    },
    /**
     *
     * @param {object} customer
     * @param normalizedContent
     */
    async handleCustomerSending(customer, normalizedContent) {
      const returnResult = {
        status: '',
      };

      if (customer.username && (!customer.toUserId || Number(customer.toUserId) === 0)) {
        try {
          const shopData = await getShopeeShopByUsername(customer.username);

          if (shopData && shopData.userid) {
            customer.toUserId = shopData.userid;
            await ShopeeMarketingSenderCustomer.updateId(
              customer._id,
              {
                toUserId: shopData.userid,
              },
              false,
            );
            this.addLog(
              'success',
              `${customer.customerName}: resolved username "${customer.username}" → userId ${shopData.userid}`,
            );
          } else {
            await this.markCustomerFailed(
              customer,
              new Error(`Cannot resolve username: ${customer.username}`),
            );
            this.addLog(
              'error',
              `${customer.customerName}: Cannot resolve username "${customer.username}"`,
            );
            returnResult.status = 'failed';
            return returnResult;
          }
        } catch (error) {
          await this.markCustomerFailed(customer, error);
          this.addLog(
            'error',
            `${customer.customerName}: ${error?.message || 'Cannot resolve username'}`,
          );
          returnResult.status = 'failed';
          return returnResult;
        }
      }

      const skipReason = await this.getSkipReason(customer);
      if (skipReason) {
        await this.markCustomerSkipped(customer, skipReason);

        this.addLog('skipped', `${customer.customerName}: ${skipReason}`);
        returnResult.status = 'skipped';
        return returnResult;
      }

      try {
        let conversationId = '';

        try {
          const getConversationResponse = await getConversationRedirection(
            customer.toUserId,
            customer.toShopId,
          );
          conversationId = getConversationResponse.conversation_id;
        } catch (error) {
          this.loggerApi.error({
            msg: 'SHOPEE_CHAT_GET_CONVERSATION_REDIRECTION_ERROR',
            error,
          });
        }

        if (conversationId) {
          await setConversationActive(conversationId, customer.toShopId).catch((error) => {
            this.loggerApi.error({
              msg: 'SHOPEE_CHAT_SET_ACTIVE_ERROR',
              error,
            });
          });
        }

        for (let contentIndex = 0; contentIndex < normalizedContent.length; contentIndex += 1) {
          const contentItem = normalizedContent[contentIndex];

          const payloadSend = {};
          if (contentItem.type === 'text' && contentItem.text && contentItem.text.trim()) {
            payloadSend.text = contentItem.text;
          } else if (
            contentItem.type === 'sticker'
              && contentItem.payload
              && contentItem.payload.stickerId
              && contentItem.payload.stickerPackage
          ) {
            payloadSend.stickerId = contentItem.payload.stickerId;
            payloadSend.stickerPackage = contentItem.payload.stickerPackage;
          } else if (
            contentItem.type === 'image'
              && contentItem.payload
              && contentItem.payload.imageId
          ) {
            payloadSend.imageId = contentItem.payload.imageId;
            payloadSend.imageUrl = contentItem.payload.imageUrl;
          } else if (
            contentItem.type === 'product'
              && contentItem.payload
              && contentItem.payload.productId
          ) {
            payloadSend.productId = contentItem.payload.productId;
            payloadSend.productName = contentItem.payload.productName;
            payloadSend.shopId = contentItem.payload.shopId || this.getShopeeShopId;
          } else if (
            contentItem.type === 'voucher'
              && contentItem.payload
              && contentItem.payload.voucherId
          ) {
            payloadSend.voucherId = contentItem.payload.voucherId;
            payloadSend.voucherCode = contentItem.payload.voucherCode;
          }

          const response = await sendChatMessage(
            customer.toUserId,
            customer.toShopId,
            contentItem.text,
            contentItem.type,
            payloadSend,
          );
          conversationId = response.conversation_id;

          this.logDelaySeconds(CONFIG_SEND.delayPerContent / 1000);
          await this.sleep(CONFIG_SEND.delayPerContent);
        }

        if (conversationId) {
          await setConversationClosed(conversationId, customer.toShopId).catch((error) => {
            this.loggerApi.error({
              msg: 'SHOPEE_CHAT_SET_CLOSED_ERROR',
              error,
            });
          });
        }

        const messageParts = normalizedContent
          .map((item) => {
            if (item.type === 'text' && item.text && item.text.trim()) {
              return item.text;
            }

            return this.$t(`SEND_MESSAGE_CONTENT_TYPE.${item.type}`);
          })
          .filter((part) => part !== null);

        const messageText = messageParts.join('\n');

        await this.markCustomerSent(customer, messageText);

        this.addLog('success', this.$t('SEND_MESSAGE_LOG_SENT', { name: customer.customerName }));

        returnResult.status = 'sent';
        return returnResult;
      } catch (error) {
        await this.markCustomerFailed(customer, error);
        this.addLog(
          'error',
          this.$t('SEND_MESSAGE_LOG_FAILED', {
            name: customer.customerName,
            error: error?.message || error?.toString() || 'ERROR',
          }),
        );
        returnResult.status = 'failed';
        return returnResult;
      }
    },
    async handleDelayAfterCustomer(sentSincePause) {
      if (sentSincePause >= this.getPauseAfterCount()) {
        this.logDelaySeconds(this.configSend.pauseDurationSeconds);
        await this.sleepSeconds(this.configSend.pauseDurationSeconds);
        return 0;
      }
      this.logDelaySeconds(this.configSend.delayBetweenSeconds);
      await this.sleepSeconds(this.configSend.delayBetweenSeconds);
      return sentSincePause;
    },
    logDelaySeconds(seconds) {
      if (!seconds || seconds <= 0) {
        return;
      }
      this.addLog('warning', this.$t('SEND_MESSAGE_LOG_DELAY', { seconds }));
    },
    logSkipDuplicate(customer, time) {
      if (!customer) {
        return;
      }
      const name = customer.customerName || customer.toUserId || this.$t('ORDER_BUYER_NAME');
      this.addLog('warning', this.$t('SEND_MESSAGE_LOG_SKIP_DUPLICATE', { name, time }));
    },
    async saveConfigSilently() {
      try {
        const payload = {
          configSend: this.normalizeConfig(this.configSend),
          listContent: this.normalizeListContent(this.listContent),
        };
        await ShopeeMarketingSenderCollect.updateId(this.collectId, payload, false);
      } catch (error) {
        this.loggerApi.error('Save config silent error:', error);
      }
    },
    async getQueueCustomers() {
      const where = {
        collectId: this.collectId,
        status: 'pending',
      };

      const limit = 200;
      let skip = 0;

      const queue = [];

      while (true) {
        const chunk = await ShopeeMarketingSenderCustomer.findMany(where, limit, skip);

        if (!chunk.length) {
          break;
        }

        chunk.forEach((item) => {
          if (item.active === false) {
            return;
          }
          queue.push(item);
        });

        if (chunk.length < limit) {
          break;
        }

        skip += limit;
      }

      return queue;
    },
    getPauseAfterCount() {
      const count = Number(this.configSend.pauseAfterCount || 0);
      if (count <= 0) {
        return Number.MAX_SAFE_INTEGER;
      }
      return count;
    },
    getMaxSendCount() {
      const count = Number(this.configSend.maxSendCount || 0);
      if (count <= 0) {
        return Number.MAX_SAFE_INTEGER;
      }
      return count;
    },
    getCustomerKvKey(customer) {
      return `${this.getShopeeShopId}:${customer.toUserId}`;
    },
    async getCustomerLastSentAt(customer) {
      const kvKey = this.getCustomerKvKey(customer);

      if (!kvKey) {
        return customer?.sentAt || 0;
      }

      try {
        const KVSenderCustomer = new KVShopeeMarketingSenderCustomer(kvKey);

        const cacheData = await KVSenderCustomer.get();

        if (cacheData && cacheData.sentAt) {
          return Number(cacheData.sentAt) || 0;
        }
      } catch (error) {
        this.loggerApi.error('KV get customer sent at error:', error);
      }
      return customer?.sentAt || 0;
    },
    async cacheCustomerSentAt(customer, sentAt) {
      const kvKey = this.getCustomerKvKey(customer);

      if (!kvKey) {
        return;
      }

      try {
        const KVSenderCustomer = new KVShopeeMarketingSenderCustomer(kvKey);

        await KVSenderCustomer.set({
          sentAt,
          updatedAt: Date.now(),
        });
      } catch (error) {
        this.loggerApi.error('KV set customer sent at error:', error);
      }
    },
    async getSkipReason(customer) {
      if (customer.active === false) {
        return this.$t('SEND_MESSAGE_SKIP_INACTIVE');
      }

      const minutes = Number(this.configSend.duplicateCooldownMinutes || 0);

      if (!minutes) {
        return '';
      }

      const lastSentAt = await this.getCustomerLastSentAt(customer);

      if (!lastSentAt) {
        return '';
      }

      const diff = Date.now() - lastSentAt;

      const threshold = minutes * 60 * 1000;

      if (diff < threshold) {
        const timeStr = this.formatDate(lastSentAt);
        this.logSkipDuplicate(customer, timeStr);
        return this.$t('SEND_MESSAGE_SKIP_COOLDOWN', { time: timeStr });
      }

      return '';
    },
    async markCustomerSent(customer, message) {
      const sentAt = Date.now();
      await ShopeeMarketingSenderCustomer.updateId(
        customer._id,
        {
          status: 'sent',
          error: '',
          message,
          sentAt,
        },
        false,
      );
      await this.cacheCustomerSentAt(customer, sentAt);
      const newSent = (this.collectData.sentCount || 0) + 1;
      await this.updateCollectMetric('sentCount', newSent);
    },
    async markCustomerSkipped(customer, reason) {
      await ShopeeMarketingSenderCustomer.updateId(
        customer._id,
        {
          status: 'skipped',
          error: reason || '',
          updatedAt: Date.now(),
        },
        false,
      );
      const newSkipped = (this.collectData.skippedCount || 0) + 1;
      await this.updateCollectMetric('skippedCount', newSkipped);
    },
    async markCustomerFailed(customer, error) {
      const errorMessage = error?.message || error?.toString() || 'ERROR';
      await ShopeeMarketingSenderCustomer.updateId(
        customer._id,
        {
          status: 'failed',
          error: errorMessage,
        },
        false,
      );
      const newFailed = (this.collectData.failedCount || 0) + 1;
      await this.updateCollectMetric('failedCount', newFailed);
    },
    async updateCollectMetric(field, value) {
      this.collectData[field] = value;
      await ShopeeMarketingSenderCollect.updateId(
        this.collectId,
        {
          [field]: value,
        },
        false,
      );
    },
    async updateCollectStatus(status) {
      await ShopeeMarketingSenderCollect.updateId(
        this.collectId,
        {
          status,
        },
        false,
      );
      this.collectData.status = status;
    },
    async resendSkippedCustomers() {
      if (this.sending || this.resendingSkipped) {
        return;
      }

      this.resendingSkipped = true;

      try {
        const where = {
          collectId: this.collectId,
          status: 'skipped',
        };

        const limit = 200;
        let skip = 0;
        let totalReset = 0;

        while (true) {
          const chunk = await ShopeeMarketingSenderCustomer.findMany(where, limit, skip);

          if (!chunk.length) {
            break;
          }

          await Promise.all(
            chunk.map(async (customer) => {
              if (customer.active === false) {
                return;
              }
              await ShopeeMarketingSenderCustomer.updateId(
                customer._id,
                {
                  status: 'pending',
                  error: '',
                  updatedAt: Date.now(),
                },
                false,
              );
              totalReset += 1;
            }),
          );

          if (chunk.length < limit) {
            break;
          }

          skip += limit;
        }

        if (totalReset > 0) {
          const newSkipped = Math.max(0, (this.collectData.skippedCount || 0) - totalReset);
          await this.updateCollectMetric('skippedCount', newSkipped);
          this.$Message.success(
            this.$t('SEND_MESSAGE_RESEND_SKIPPED_SUCCESS', { count: totalReset }),
          );
          this.addLog(
            'success',
            this.$t('SEND_MESSAGE_RESEND_SKIPPED_SUCCESS', { count: totalReset }),
          );
          await this.fetchCollect();
          await this.fetchCustomers();
        } else {
          this.$Message.info(this.$t('SEND_MESSAGE_NO_SKIPPED_CUSTOMERS'));
        }
      } catch (error) {
        this.$Message.error(this.$t('SEND_MESSAGE_RESEND_SKIPPED_ERROR'));
        this.loggerApi.error('Resend skipped customers error:', error);
        this.addLog('error', this.$t('SEND_MESSAGE_RESEND_SKIPPED_ERROR'));
      } finally {
        this.resendingSkipped = false;
      }
    },
    sleep(ms) {
      if (!ms || ms <= 0) {
        return Promise.resolve();
      }
      return new Promise((resolve) => {
        setTimeout(resolve, ms);
      });
    },
    sleepSeconds(seconds) {
      if (!seconds || seconds <= 0) {
        return Promise.resolve();
      }
      return this.sleep(seconds * 1000);
    },
    addLog(type, message) {
      this.log.unshift({
        type,
        message,
        time: Date.now(),
      });
      if (this.log.length > 200) {
        this.log.pop();
      }
    },
    formatDate(timestamp) {
      if (!timestamp) {
        return '-';
      }
      const date = new Date(timestamp);
      return date.toLocaleString('vi-VN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
      });
    },
    getCustomerStatusColor(status) {
      const colorMap = {
        pending: 'default',
        sent: 'success',
        failed: 'error',
        skipped: 'warning',
      };
      return colorMap[status] || 'primary';
    },
    getStatusColor(status) {
      const colorMap = {
        pending: 'default',
        sending: 'primary',
        completed: 'success',
        failed: 'error',
      };
      return colorMap[status] || 'primary';
    },
    getLogIconType(type) {
      const iconMap = {
        success: 'ios-checkmark-circle',
        error: 'ios-close-circle',
        warning: 'ios-alert',
        skipped: 'ios-information-circle',
      };
      if (iconMap[type]) {
        return iconMap[type];
      }
      return 'ios-information-circle';
    },
    getLogColorType(type) {
      const colorMap = {
        success: 'success',
        error: 'error',
        warning: 'warning',
        skipped: 'warning',
      };
      if (colorMap[type]) {
        return colorMap[type];
      }
      return 'primary';
    },
  },
  created() {
    this.createdHook();

    ShopeeMarketingSenderCollect.syncRemote();
    ShopeeMarketingSenderCustomer.syncRemote();
  },
};
</script>

<style scoped>
  .mb-20 {
    margin-bottom: 20px;
  }

  .mt-10 {
    margin-top: 10px;
  }

  .mt-20 {
    margin-top: 20px;
  }

  .ml-5 {
    margin-left: 5px;
  }

  .ml-10 {
    margin-left: 10px;
  }

  .mr-10 {
    margin-right: 10px;
  }

  .text-success {
    color: #19be6b;
  }

  .text-error {
    color: #ed4014;
  }

  .text-warning {
    color: #ff9900;
  }

  .stat-item {
    text-align: center;
    padding: 16px;
    background-color: #f8f9fa;
    border-radius: 6px;
    border: 1px solid #e9ecef;
  }

  .stat-label {
    font-size: 14px;
    color: #666;
    margin-bottom: 8px;
    font-weight: 500;
  }

  .stat-value {
    font-size: 24px;
    font-weight: 600;
    color: #333;
  }

  .log-container {
    max-height: 400px;
    overflow-y: auto;
    padding: 10px;
    background-color: #fafafa;
    border-radius: 4px;
  }

  .log-item {
    padding: 8px 12px;
    margin-bottom: 8px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    font-size: 14px;
    line-height: 1.5;
  }

  .log-success {
    background-color: #f0f9ff;
    border-left: 3px solid #19be6b;
  }

  .log-error {
    background-color: #fff1f0;
    border-left: 3px solid #ed4014;
  }

  .log-warning,
  .log-skipped {
    background-color: #fffbe6;
    border-left: 3px solid #ff9900;
  }

  .empty-log {
    text-align: center;
    padding: 48px 24px;
    color: #999;
  }

  .empty-log .empty-icon {
    color: #ddd;
    margin-bottom: 16px;
  }

  .empty-log .empty-text {
    margin: 0;
    font-size: 16px;
  }

  .config-label {
    font-size: 14px;
    color: #515a6e;
    margin-bottom: 8px;
    font-weight: 500;
  }

  .config-label.compact {
    margin-bottom: 0;
  }

  .action-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
  }

  .action-toolbar__config {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
    min-width: 260px;
  }

  .action-toolbar__buttons {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
  }

  .content-scroll-container {
    max-height: 500px;
    overflow-y: auto;
    padding-right: 8px;
  }

  .content-scroll-container::-webkit-scrollbar {
    width: 6px;
  }

  .content-scroll-container::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }

  .content-scroll-container::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;
  }

  .content-scroll-container::-webkit-scrollbar-thumb:hover {
    background: #a8a8a8;
  }

  .empty-customer-container {
    padding: 80px 20px;
    text-align: center;
    background-color: #fff;
    border-radius: 8px;
    border: 1px dashed #d9d9d9;
  }

  .empty-customer-icon {
    color: #d9d9d9;
    margin-bottom: 16px;
  }

  .empty-customer-title {
    font-size: 20px;
    margin-bottom: 8px;
    color: #515a6e;
  }

  .empty-customer-desc {
    margin: 0;
    color: #808695;
  }
</style>
