<template>
  <div class="sv-dash">
    <div
      v-if="noShop"
      class="sv-dash__empty"
    >
      <Icon type="ios-alert-outline" />
      <p>{{ $t('SHOPEE_VIDEO_DASH_NO_SHOP') }}</p>
    </div>

    <template v-else>
      <div class="sv-dash__toolbar">
        <Button
          type="primary"
          size="small"
          icon="md-add"
          class="sv-dash__bulk"
          @click="goBulkCreate"
        >
          {{ $t('SHOPEE_VIDEO_BULK_ENTRY') }}
        </Button>
        <Button
          type="text"
          size="small"
          icon="ios-stats-outline"
          class="sv-dash__link"
          @click="openExternalUrl(shopVideoInsightUrl)"
        >
          {{ $t('SHOPEE_VIDEO_DASH_LINK_INSIGHT') }}
        </Button>
        <Button
          type="text"
          size="small"
          icon="ios-albums-outline"
          class="sv-dash__link"
          @click="openExternalUrl(shopVideoManageUrl)"
        >
          {{ $t('SHOPEE_VIDEO_DASH_LINK_MANAGE') }}
        </Button>
      </div>

      <div class="sv-dash__stats">
        <div class="sv-stat">
          <span class="sv-stat__label">{{ $t('SHOPEE_VIDEO_DASH_STATS_CAMPAIGNS') }}</span>
          <span class="sv-stat__value">{{ stats.campaigns }}</span>
        </div>
        <div class="sv-stat">
          <span class="sv-stat__label">{{ $t('SHOPEE_VIDEO_DASH_STATS_ITEMS') }}</span>
          <span class="sv-stat__value">{{ stats.items }}</span>
        </div>
        <div class="sv-stat is-done">
          <span class="sv-stat__label">{{ $t('SHOPEE_VIDEO_DASH_STATS_DONE') }}</span>
          <span class="sv-stat__value">{{ stats.done }}</span>
        </div>
        <div class="sv-stat is-error">
          <span class="sv-stat__label">{{ $t('SHOPEE_VIDEO_DASH_STATS_ERROR') }}</span>
          <span class="sv-stat__value">{{ stats.error }}</span>
        </div>
        <div class="sv-stat is-pending">
          <span class="sv-stat__label">{{ $t('SHOPEE_VIDEO_DASH_STATS_PENDING') }}</span>
          <span class="sv-stat__value">{{ stats.pending }}</span>
        </div>
      </div>

      <div class="sv-dash__body">
        <div class="sv-dash__side">
          <div class="sv-dash__side-head">
            <h3 class="sv-dash__side-title">
              {{ $t('SHOPEE_VIDEO_DASH_CAMPAIGN_LIST') }}
            </h3>
            <div class="sv-dash__side-actions">
              <Button
                type="text"
                size="small"
                icon="md-refresh"
                :loading="loadingCampaigns"
                :title="$t('SHOPEE_VIDEO_DASH_REFRESH')"
                @click="refresh"
              />
              <Button
                type="primary"
                size="small"
                icon="md-add"
                @click="openCampaignCreate"
              >
                {{ $t('SHOPEE_VIDEO_CAMPAIGN_CREATE') }}
              </Button>
            </div>
          </div>

          <div
            v-if="!campaigns.length"
            class="sv-dash__side-empty"
          >
            {{ $t('SHOPEE_VIDEO_DASH_CAMPAIGN_EMPTY') }}
          </div>

          <ul
            v-else
            class="sv-campaigns"
          >
            <li
              v-for="campaign in campaigns"
              :key="campaign._id"
              class="sv-campaign"
              :class="{ 'is-active': campaign._id === activeCampaignId }"
              @click="selectCampaign(campaign._id)"
            >
              <div class="sv-campaign__info">
                <span class="sv-campaign__name">{{ campaign.name }}</span>
                <span class="sv-campaign__meta">
                  {{ $t('SHOPEE_VIDEO_DASH_CAMPAIGN_COUNT', { count: campaign.totalItems || 0 }) }}
                </span>
              </div>
              <div
                class="sv-campaign__actions"
                @click.stop
              >
                <Button
                  type="text"
                  size="small"
                  icon="md-create"
                  :title="$t('SHOPEE_VIDEO_DASH_CAMPAIGN_RENAME')"
                  @click="openCampaignEdit(campaign)"
                />
                <Poptip
                  confirm
                  transfer
                  placement="left"
                  :title="$t('SHOPEE_VIDEO_DASH_CAMPAIGN_DELETE_CONFIRM')"
                  @on-ok="removeCampaign(campaign)"
                >
                  <Button
                    type="text"
                    size="small"
                    icon="md-trash"
                    :title="$t('SHOPEE_VIDEO_DASH_CAMPAIGN_DELETE')"
                  />
                </Poptip>
              </div>
            </li>
          </ul>
        </div>

        <div class="sv-dash__main">
          <div
            v-if="!activeCampaignId"
            class="sv-dash__main-empty"
          >
            {{ $t('SHOPEE_VIDEO_DASH_SELECT_CAMPAIGN') }}
          </div>

          <template v-else>
            <div class="sv-dash__mainbar">
              <RadioGroup
                v-model="statusFilter"
                type="button"
                class="sv-dash__filter"
              >
                <Radio label="all">
                  {{ $t('SHOPEE_VIDEO_DASH_FILTER_ALL') }}
                </Radio>
                <Radio label="done">
                  {{ $t('SHOPEE_VIDEO_DASH_FILTER_DONE') }}
                </Radio>
                <Radio label="error">
                  {{ $t('SHOPEE_VIDEO_DASH_FILTER_ERROR') }}
                </Radio>
                <Radio label="pending">
                  {{ $t('SHOPEE_VIDEO_DASH_FILTER_PENDING') }}
                </Radio>
              </RadioGroup>
              <div class="sv-dash__publish-all">
                <span
                  v-if="publishingAll"
                  class="sv-dash__publish-prog"
                >{{ $t('SHOPEE_VIDEO_DASH_PUBLISH_PROGRESS', { current: publishDone, total: publishTotal }) }}</span>
                <Button
                  type="error"
                  size="small"
                  icon="md-cloud-upload"
                  :loading="publishingAll"
                  :disabled="!pendingCount"
                  @click="publishAll"
                >
                  {{ $t('SHOPEE_VIDEO_DASH_PUBLISH_ALL', { count: pendingCount }) }}
                </Button>
              </div>
            </div>

            <div class="sv-list">
              <div
                v-if="loadingItems"
                class="sv-list__state"
              >
                <Spin />
              </div>
              <div
                v-else-if="!visibleItems.length"
                class="sv-list__state"
              >
                <Icon
                  type="ios-film-outline"
                  class="sv-list__state-icon"
                />
                <p>{{ $t('SHOPEE_VIDEO_DASH_ITEMS_EMPTY') }}</p>
              </div>

              <div
                v-for="item in visibleItems"
                v-else
                :key="item._id"
                class="sv-card"
                :class="`is-${normalizeStatus(item)}`"
              >
                <div class="sv-card__body">
                  <div
                    class="sv-thumb"
                    @click="openPreview(item)"
                  >
                    <video
                      v-if="thumbSrc(item)"
                      class="sv-thumb__video"
                      :src="thumbSrc(item)"
                      muted
                      playsinline
                      preload="metadata"
                      @error="onThumbError"
                    />
                    <div class="sv-thumb__ph">
                      <Spin v-if="item.previewLoading" />
                      <Icon
                        v-else
                        type="ios-play"
                        class="sv-thumb__play"
                      />
                    </div>
                    <span
                      class="sv-thumb__src"
                      :class="`is-${item.source}`"
                    >{{ sourceLabel(item.source) }}</span>
                    <span
                      v-if="durationText(item)"
                      class="sv-thumb__dur"
                    >{{ durationText(item) }}</span>
                  </div>

                  <div class="sv-card__main">
                    <div class="sv-card__head">
                      <span
                        class="sv-card__caption"
                        :title="item.caption"
                      >{{ item.caption || '—' }}</span>
                      <Button
                        type="text"
                        size="small"
                        icon="md-create"
                        class="sv-card__edit"
                        :title="$t('SHOPEE_VIDEO_DASH_ACT_EDIT')"
                        @click="openEdit(item)"
                      />
                    </div>

                    <div class="sv-card__meta">
                      <span
                        class="sv-badge"
                        :class="`is-${normalizeStatus(item)}`"
                      >
                        <i class="sv-badge__dot" />
                        {{ statusText(item) }}
                      </span>
                      <span class="sv-chip">
                        <Icon type="ios-time-outline" />
                        {{ formatDate(item.postedAt) }}
                      </span>
                      <span class="sv-chip">
                        <Icon type="ios-cube-outline" />
                        {{ productCount(item) }} {{ $t('SHOPEE_VIDEO_DASH_COL_PRODUCTS') }}
                      </span>
                      <a
                        v-if="item.videoId"
                        class="sv-chip sv-chip--id"
                        :title="$t('SHOPEE_VIDEO_DASH_VIEW_INSIGHT')"
                        @click="openVideoInsight(item)"
                      >
                        <Icon type="ios-stats-outline" />
                        ID: {{ item.videoId }}
                      </a>
                      <a
                        v-if="productCount(item)"
                        class="sv-card__toggle"
                        @click="toggleProducts(item)"
                      >
                        {{ viewLabel(item) }}
                        <Icon :type="item.showProducts ? 'ios-arrow-up' : 'ios-arrow-down'" />
                      </a>
                      <a
                        v-if="item.previewError"
                        class="sv-card__err"
                        :href="item.sourceUrl"
                        target="_blank"
                        rel="noopener"
                      >{{ $t('SHOPEE_VIDEO_DASH_PREVIEW_OPEN') }}</a>
                    </div>

                    <div
                      v-if="normalizeStatus(item) === 'done'"
                      class="sv-card__metrics"
                    >
                      <span
                        class="sv-metric"
                        :title="$t('SHOPEE_VIDEO_DASH_METRIC_VIEWS')"
                      >
                        <Icon type="ios-eye-outline" />
                        {{ formatCompact(item.viewCount) }}
                      </span>
                      <span
                        class="sv-metric"
                        :title="$t('SHOPEE_VIDEO_DASH_METRIC_LIKES')"
                      >
                        <Icon type="ios-heart-outline" />
                        {{ formatCompact(item.likeCount) }}
                      </span>
                      <span
                        class="sv-metric"
                        :title="$t('SHOPEE_VIDEO_DASH_METRIC_COMMENTS')"
                      >
                        <Icon type="ios-chatbubbles-outline" />
                        {{ formatCompact(item.commentCount) }}
                      </span>
                      <span
                        class="sv-metric"
                        :title="$t('SHOPEE_VIDEO_DASH_METRIC_SHARES')"
                      >
                        <Icon type="ios-share-outline" />
                        {{ formatCompact(item.shareCount) }}
                      </span>
                      <span
                        class="sv-metric is-sold"
                        :title="$t('SHOPEE_VIDEO_DASH_METRIC_SOLD')"
                      >
                        <Icon type="ios-pricetags-outline" />
                        {{ formatCompact(item.soldCount) }}
                      </span>
                      <span class="sv-card__synced">{{ syncedLabel(item) }}</span>
                    </div>
                  </div>

                  <div class="sv-card__act">
                    <Button
                      v-if="canRepost(item)"
                      type="primary"
                      size="small"
                      class="sv-card__post"
                      :loading="repostingId === item._id"
                      @click="repost(item)"
                    >
                      {{ repostLabel(item) }}
                    </Button>
                    <Button
                      v-if="false"
                      type="default"
                      size="small"
                      icon="md-refresh"
                      class="sv-card__sync"
                      :loading="syncingId === item._id"
                      :title="$t('SHOPEE_VIDEO_DASH_SYNC')"
                      @click="syncMetrics(item)"
                    >
                      {{ $t('SHOPEE_VIDEO_DASH_SYNC') }}
                    </Button>
                    <Poptip
                      confirm
                      transfer
                      placement="left"
                      :title="$t('SHOPEE_VIDEO_DASH_DELETE_CONFIRM')"
                      @on-ok="removeItem(item)"
                    >
                      <Button
                        type="text"
                        size="small"
                        class="sv-card__del"
                      >
                        {{ $t('SHOPEE_VIDEO_DASH_ACT_DELETE') }}
                      </Button>
                    </Poptip>
                  </div>
                </div>

                <div
                  v-if="item.showProducts"
                  class="sv-card__products"
                >
                  <div
                    v-for="product in (item.products || [])"
                    :key="product.itemId"
                    class="sv-prod"
                  >
                    <img
                      class="sv-prod__img"
                      :src="productImage(product.cover)"
                      @error="onImgError"
                    >
                    <div class="sv-prod__info">
                      <span
                        class="sv-prod__name"
                        :title="product.name"
                      >{{ product.name }}</span>
                      <span class="sv-prod__price">{{ productPrice(product) }}</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </template>
        </div>
      </div>
    </template>

    <Modal
      v-model="previewModal.show"
      :title="$t('SHOPEE_VIDEO_DASH_COL_VIDEO')"
      footer-hide
      @on-cancel="onPreviewClose"
    >
      <video
        v-if="previewModal.url"
        :src="previewModal.url"
        controls
        autoplay
        class="sv-preview-video"
      />
    </Modal>

    <Modal
      v-model="editModal.show"
      :title="$t('SHOPEE_VIDEO_DASH_EDIT_TITLE')"
      :loading="editModal.saving"
      @on-ok="saveEdit"
    >
      <Input
        v-model="editModal.caption"
        type="textarea"
        :rows="4"
        :placeholder="$t('SHOPEE_VIDEO_CAPTION_PLACEHOLDER')"
      />
    </Modal>

    <Modal
      v-model="campaignModal.show"
      :title="campaignModalTitle"
      :loading="campaignModal.saving"
      @on-ok="saveCampaign"
    >
      <Input
        v-model="campaignModal.name"
        :placeholder="$t('SHOPEE_VIDEO_CAMPAIGN_NEW')"
        @on-enter="saveCampaign"
      />
    </Modal>
  </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import { getShopeeSellerInfo } from '@/api/shopee/seller/get';
import {
  publishAndSyncVideo, deleteVideo, getVideoList, getVideoDetail, buildVideoInfoPatch,
} from '@/api/shopee/seller/video';
import {
  apiShopeeVideoCampaignList,
  apiShopeeVideoCampaignStats,
  apiShopeeVideoCampaignCreate,
  apiShopeeVideoCampaignUpdate,
  apiShopeeVideoCampaignRemove,
  apiShopeeVideoItemList,
  apiShopeeVideoItemUpdate,
  apiShopeeVideoItemRemove,
} from '@/api/autoshopee/shopee/shopeeVideo';
import { imageUrl } from '@/adapter/shopee/render/utils';
import { loggerShopee } from '@/plugins/logger';
import { SHOPEE_VIDEO_INSIGHT_URL, SHOPEE_VIDEO_MANAGE_URL } from '@/constant/shopee';

const EMPTY_STATS = {
  campaigns: 0,
  items: 0,
  done: 0,
  error: 0,
  pending: 0,
};

const METRICS_TTL_MS = 5 * 60 * 1000;
const AUTO_SYNC_INTERVAL_MS = 60 * 1000;
const AUTO_SYNC_GAP_MS = 500;

export default defineComponent({
  data() {
    return {
      shopId: '',
      shopName: '',
      noShop: false,
      shopVideoInsightUrl: SHOPEE_VIDEO_INSIGHT_URL,
      shopVideoManageUrl: SHOPEE_VIDEO_MANAGE_URL,
      stats: { ...EMPTY_STATS },
      campaigns: [],
      activeCampaignId: '',
      items: [],
      statusFilter: 'all',
      loadingCampaigns: false,
      loadingItems: false,
      repostingId: '',
      syncingId: '',
      autoSyncing: false,
      autoSyncTimer: null,
      publishingAll: false,
      publishDone: 0,
      publishTotal: 0,
      editModal: {
        show: false,
        itemId: '',
        caption: '',
        saving: false,
      },
      campaignModal: {
        show: false,
        mode: 'create',
        id: '',
        name: '',
        saving: false,
      },
      previewModal: {
        show: false,
        url: '',
      },
    };
  },
  computed: {
    visibleItems() {
      const list = [];

      this.items.forEach((item) => {
        const status = this.normalizeStatus(item);

        if (status === 'archived') {
          return;
        }

        if (this.statusFilter !== 'all' && status !== this.statusFilter) {
          return;
        }

        list.push(item);
      });

      return list;
    },
    campaignModalTitle() {
      if (this.campaignModal.mode === 'rename') {
        return this.$t('SHOPEE_VIDEO_DASH_CAMPAIGN_EDIT_TITLE');
      }

      return this.$t('SHOPEE_VIDEO_CAMPAIGN_NEW_LINK');
    },
    pendingItems() {
      return this.items.filter((item) => {
        return this.normalizeStatus(item) === 'pending';
      });
    },
    pendingCount() {
      return this.pendingItems.length;
    },
  },
  async created() {
    await this.init();

    this.autoSyncTimer = setInterval(() => {
      this.autoSyncStale();
    }, AUTO_SYNC_INTERVAL_MS);
  },
  beforeDestroy() {
    if (this.autoSyncTimer) {
      clearInterval(this.autoSyncTimer);
    }

    this.items.forEach((item) => {
      if (item.previewUrl) {
        URL.revokeObjectURL(item.previewUrl);
      }
    });
  },
  methods: {
    openVideoInsight(item) {
      if (!item.videoId) {
        return;
      }

      this.openExternalUrl(`${SHOPEE_VIDEO_INSIGHT_URL}/${item.videoId}`);
    },
    canSync(item) {
      if (this.normalizeStatus(item) !== 'done') {
        return false;
      }

      return !!item.videoId;
    },
    formatCompact(value) {
      const num = Number(value) || 0;

      if (num >= 1000000) {
        return `${(num / 1000000).toFixed(1).replace(/\.0$/, '')}M`;
      }

      if (num >= 1000) {
        return `${(num / 1000).toFixed(1).replace(/\.0$/, '')}K`;
      }

      return `${num}`;
    },
    syncedLabel(item) {
      if (!item.metricsSyncedAt) {
        return this.$t('SHOPEE_VIDEO_DASH_METRIC_NEVER');
      }

      return this.$t('SHOPEE_VIDEO_DASH_METRIC_SYNCED', { time: this.formatDate(item.metricsSyncedAt) });
    },
    async syncMetrics(item) {
      if (this.syncingId || !item.videoId) {
        return;
      }

      this.syncingId = item._id;

      try {
        const detail = await getVideoDetail(item.videoId);

        if (!detail) {
          throw new Error('NO_DETAIL');
        }

        const patch = buildVideoInfoPatch(detail);
        const updated = await apiShopeeVideoItemUpdate(item._id, patch);

        if (!updated) {
          throw new Error('UPDATE_FAILED');
        }

        this.applyPatch(item._id, patch);
        this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_SYNC_SUCCESS'));
      } catch (error) {
        loggerShopee.error({
          msg: 'SHOPEE_VIDEO_SYNC_METRICS_ERROR',
          error,
          videoId: item.videoId,
        });

        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_SYNC_ERROR'));
      }

      this.syncingId = '';
    },
    needsMetricSync(item) {
      if (this.normalizeStatus(item) !== 'done') {
        return false;
      }

      if (!item.videoId) {
        return false;
      }

      if (!item.metricsSyncedAt) {
        return true;
      }

      const last = new Date(item.metricsSyncedAt).getTime();

      if (Number.isNaN(last)) {
        return true;
      }

      return (Date.now() - last) > METRICS_TTL_MS;
    },
    async syncMetricsSilent(item) {
      if (!item.videoId) {
        return;
      }

      try {
        const detail = await getVideoDetail(item.videoId);

        if (!detail) {
          return;
        }

        const patch = buildVideoInfoPatch(detail);
        const updated = await apiShopeeVideoItemUpdate(item._id, patch);

        if (!updated) {
          return;
        }

        this.applyPatch(item._id, patch);
      } catch (error) {
        loggerShopee.error({
          msg: 'SHOPEE_VIDEO_AUTO_SYNC_ERROR',
          error,
          videoId: item.videoId,
        });
      }
    },
    async autoSyncStale() {
      if (this.autoSyncing) {
        return;
      }

      const targets = this.items.filter((item) => {
        return this.needsMetricSync(item);
      });

      if (!targets.length) {
        return;
      }

      this.autoSyncing = true;

      for (let i = 0; i < targets.length; i += 1) {
        await this.syncMetricsSilent(targets[i]);
        await new Promise((resolve) => {
          setTimeout(resolve, AUTO_SYNC_GAP_MS);
        });
      }

      this.autoSyncing = false;
    },
    async openPreview(item) {
      if (!item.sourceUrl) {
        return;
      }

      if (item.previewUrl) {
        this.previewModal.url = item.previewUrl;
        this.previewModal.show = true;
        return;
      }

      if (item.previewLoading) {
        return;
      }

      this.applyPatch(item._id, {
        previewLoading: true,
        previewError: false,
      });

      try {
        const response = await fetch(item.sourceUrl);

        if (!response.ok) {
          throw new Error(`HTTP_${response.status}`);
        }

        const blob = await response.blob();
        const url = URL.createObjectURL(blob);

        this.applyPatch(item._id, {
          previewUrl: url,
          previewLoading: false,
        });

        this.previewModal.url = url;
        this.previewModal.show = true;
      } catch (error) {
        loggerShopee.error({
          msg: 'SHOPEE_VIDEO_PREVIEW_ERROR',
          error,
        });

        this.applyPatch(item._id, {
          previewLoading: false,
          previewError: true,
        });
      }
    },
    onPreviewClose() {
      this.previewModal.url = '';
    },
    toggleProducts(item) {
      this.applyPatch(item._id, {
        showProducts: !item.showProducts,
      });
    },
    viewLabel(item) {
      if (item.showProducts) {
        return this.$t('SHOPEE_VIDEO_DASH_COLLAPSE');
      }

      return this.$t('SHOPEE_VIDEO_DASH_VIEW');
    },
    productCount(item) {
      if (item.products) {
        return item.products.length;
      }

      return 0;
    },
    productImage(cover) {
      return imageUrl(cover || '');
    },
    productPrice(product) {
      const snapshot = product.snapshot || {};
      return this.formatPrice(snapshot.minPrice || 0, snapshot.maxPrice || 0);
    },
    onImgError(event) {
      event.target.style.visibility = 'hidden';
    },
    thumbSrc(item) {
      if (item.previewUrl) {
        return item.previewUrl;
      }

      if (!item.sourceUrl) {
        return '';
      }

      return `${item.sourceUrl}#t=0.5`;
    },
    onThumbError(event) {
      event.target.style.display = 'none';
    },
    durationText(item) {
      const seconds = Number(item.duration) || 0;

      if (!seconds) {
        return '';
      }

      const total = Math.round(seconds);
      const mins = Math.floor(total / 60);
      const secs = total % 60;
      const mm = `${mins}`.padStart(2, '0');
      const ss = `${secs}`.padStart(2, '0');

      return `${mm}:${ss}`;
    },
    async init() {
      const sellerInfo = await getShopeeSellerInfo();

      if (sellerInfo && sellerInfo.shop_id) {
        this.shopId = `${sellerInfo.shop_id}`;
        this.shopName = sellerInfo.name || '';
      }

      if (!this.shopId) {
        this.noShop = true;
        return;
      }

      if (this.$route.query.campaignId) {
        this.activeCampaignId = `${this.$route.query.campaignId}`;
      }

      await this.loadStatsAndCampaigns();
    },
    async loadStatsAndCampaigns() {
      this.loadingCampaigns = true;
      this.stats = await apiShopeeVideoCampaignStats(this.shopId);
      this.campaigns = await apiShopeeVideoCampaignList(this.shopId);
      this.loadingCampaigns = false;

      if (!this.campaigns.length) {
        this.activeCampaignId = '';
        this.items = [];
        return;
      }

      const hasActive = this.campaigns.some((campaign) => {
        return campaign._id === this.activeCampaignId;
      });

      if (!hasActive) {
        this.activeCampaignId = this.campaigns[0]._id;
      }

      await this.loadItems();
    },
    async loadItems() {
      if (!this.activeCampaignId) {
        this.items = [];
        return;
      }

      this.loadingItems = true;
      this.items = await apiShopeeVideoItemList(this.activeCampaignId);
      this.loadingItems = false;

      this.autoSyncStale();
    },
    async refresh() {
      await this.loadStatsAndCampaigns();
    },
    async refreshStats() {
      this.stats = await apiShopeeVideoCampaignStats(this.shopId);
    },
    selectCampaign(campaignId) {
      if (campaignId === this.activeCampaignId) {
        return;
      }

      this.activeCampaignId = campaignId;
      this.statusFilter = 'all';
      this.loadItems();
    },
    goBulkCreate() {
      this.$router.push({ name: 'ShopeeVideoBulkCreate' });
    },
    async publishAll() {
      if (this.publishingAll) {
        return;
      }

      const targets = this.pendingItems.slice();

      if (!targets.length) {
        return;
      }

      this.publishingAll = true;
      this.publishTotal = targets.length;
      this.publishDone = 0;

      let success = 0;
      let failed = 0;

      for (let i = 0; i < targets.length; i += 1) {
        const target = targets[i];

        await this.repost(target);

        this.publishDone = i + 1;

        const fresh = this.items.find((row) => {
          return row._id === target._id;
        });

        if (fresh && this.normalizeStatus(fresh) === 'done') {
          success += 1;
        } else {
          failed += 1;
        }
      }

      this.publishingAll = false;
      this.$Message.info(this.$t('SHOPEE_VIDEO_DASH_PUBLISH_ALL_DONE', { success, failed }));
    },
    openCampaignCreate() {
      this.campaignModal.mode = 'create';
      this.campaignModal.id = '';
      this.campaignModal.name = '';
      this.campaignModal.show = true;
    },
    openCampaignEdit(campaign) {
      this.campaignModal.mode = 'rename';
      this.campaignModal.id = campaign._id;
      this.campaignModal.name = campaign.name || '';
      this.campaignModal.show = true;
    },
    async saveCampaign() {
      const name = this.campaignModal.name.trim();

      if (!name) {
        this.campaignModal.saving = false;
        return;
      }

      this.campaignModal.saving = true;

      if (this.campaignModal.mode === 'rename') {
        await this.submitCampaignRename(name);
      } else {
        await this.submitCampaignCreate(name);
      }

      this.campaignModal.saving = false;
    },
    async submitCampaignCreate(name) {
      const created = await apiShopeeVideoCampaignCreate({
        name,
        shopId: this.shopId,
        shopName: this.shopName,
      });

      if (created) {
        this.campaigns = [created].concat(this.campaigns);
        this.activeCampaignId = created._id;
        this.items = [];
        this.statusFilter = 'all';
        this.campaignModal.show = false;
        await this.refreshStats();
      } else {
        this.$Message.error(this.$t('SHOPEE_VIDEO_CAMPAIGN_CREATE_ERROR'));
      }
    },
    async submitCampaignRename(name) {
      const updated = await apiShopeeVideoCampaignUpdate(this.campaignModal.id, { name });

      if (updated) {
        const index = this.campaigns.findIndex((campaign) => {
          return campaign._id === this.campaignModal.id;
        });

        if (index !== -1) {
          this.campaigns.splice(index, 1, { ...this.campaigns[index], name });
        }

        this.campaignModal.show = false;
        this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_SAVE_SUCCESS'));
      } else {
        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_SAVE_ERROR'));
      }
    },
    async removeCampaign(campaign) {
      const removed = await apiShopeeVideoCampaignRemove(campaign._id);

      if (!removed) {
        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_SAVE_ERROR'));
        return;
      }

      const index = this.campaigns.findIndex((item) => {
        return item._id === campaign._id;
      });

      if (index !== -1) {
        this.campaigns.splice(index, 1);
      }

      if (this.activeCampaignId === campaign._id) {
        if (this.campaigns.length) {
          this.activeCampaignId = this.campaigns[0]._id;
          this.statusFilter = 'all';
          await this.loadItems();
        } else {
          this.activeCampaignId = '';
          this.items = [];
        }
      }

      await this.refreshStats();
      this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_DELETE_SUCCESS'));
    },
    normalizeStatus(item) {
      if (item.status === 'done') {
        return 'done';
      }

      if (item.status === 'error') {
        return 'error';
      }

      if (item.status === 'archived') {
        return 'archived';
      }

      return 'pending';
    },
    canRepost(item) {
      const status = this.normalizeStatus(item);

      if (status === 'error') {
        return true;
      }

      if (status === 'pending') {
        return true;
      }

      return false;
    },
    repostLabel(item) {
      const status = this.normalizeStatus(item);

      if (status === 'error') {
        return this.$t('SHOPEE_VIDEO_DASH_ACT_REPOST');
      }

      return this.$t('SHOPEE_VIDEO_DASH_ACT_POST');
    },
    formatPrice(minPrice, maxPrice) {
      if (!minPrice) {
        return '';
      }

      const min = Math.round(minPrice);
      const max = Math.round(maxPrice);

      if (max && max !== min) {
        return `${min.toLocaleString('vi-VN')}đ - ${max.toLocaleString('vi-VN')}đ`;
      }

      return `${min.toLocaleString('vi-VN')}đ`;
    },
    statusText(item) {
      const status = this.normalizeStatus(item);

      if (status === 'done') {
        return this.$t('SHOPEE_VIDEO_DASH_STATUS_DONE');
      }

      if (status === 'error') {
        return this.$t('SHOPEE_VIDEO_DASH_STATUS_ERROR');
      }

      if (status === 'archived') {
        return this.$t('SHOPEE_VIDEO_DASH_STATUS_ARCHIVED');
      }

      return this.$t('SHOPEE_VIDEO_DASH_STATUS_PENDING');
    },
    sourceLabel(source) {
      if (source === 'shopee') {
        return 'Shopee';
      }

      if (source === 'product') {
        return 'Sản phẩm';
      }

      return 'TikTok';
    },
    formatDate(value) {
      if (!value) {
        return '-';
      }

      const date = new Date(value);

      if (Number.isNaN(date.getTime())) {
        return '-';
      }

      return date.toLocaleString('vi-VN');
    },
    applyPatch(itemId, patch) {
      const index = this.items.findIndex((item) => {
        return item._id === itemId;
      });

      if (index === -1) {
        return;
      }

      this.items.splice(index, 1, { ...this.items[index], ...patch });
    },
    buildProductList(item) {
      const products = item.products || [];

      return products.map((product) => {
        const snapshot = product.snapshot || {};

        return {
          itemId: Number(product.itemId),
          name: product.name,
          cover: product.cover,
          minPrice: snapshot.minPrice,
          maxPrice: snapshot.maxPrice,
          status: snapshot.status,
          stock: snapshot.stock,
          shopId: Number(this.shopId),
        };
      });
    },
    async repost(item) {
      if (this.repostingId) {
        return;
      }

      this.repostingId = item._id;
      this.$Message.info(this.$t('SHOPEE_VIDEO_DASH_REPOST_PROCESSING'));

      try {
        const response = await fetch(item.sourceUrl);
        const blob = await response.blob();
        const productList = this.buildProductList(item);

        const { vid, videoId, infoPatch } = await publishAndSyncVideo(blob, {
          caption: item.caption,
          productList,
        });

        const postedAt = new Date().toISOString();

        await apiShopeeVideoItemUpdate(item._id, {
          status: 'done',
          mmsVid: vid,
          videoId,
          postedAt,
          ...infoPatch,
        });

        this.applyPatch(item._id, {
          status: 'done',
          mmsVid: vid,
          videoId,
          postedAt,
          ...infoPatch,
        });

        this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_REPOST_SUCCESS'));
        await this.refreshStats();
      } catch (error) {
        loggerShopee.error({
          msg: 'SHOPEE_VIDEO_REPOST_ERROR',
          error,
        });

        await apiShopeeVideoItemUpdate(item._id, {
          status: 'error',
          errorMsg: `${error && error.message ? error.message : error}`.slice(0, 200),
        });

        this.applyPatch(item._id, {
          status: 'error',
        });

        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_REPOST_ERROR'));
        await this.refreshStats();
      }

      this.repostingId = '';
    },
    openEdit(item) {
      this.editModal.itemId = item._id;
      this.editModal.caption = item.caption || '';
      this.editModal.show = true;
    },
    async saveEdit() {
      this.editModal.saving = true;

      const updated = await apiShopeeVideoItemUpdate(this.editModal.itemId, {
        caption: this.editModal.caption,
      });

      if (updated) {
        this.applyPatch(this.editModal.itemId, {
          caption: this.editModal.caption,
        });
        this.editModal.show = false;
        this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_SAVE_SUCCESS'));
      } else {
        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_SAVE_ERROR'));
      }

      this.editModal.saving = false;
    },
    async resolveShopeeVideoId(item) {
      if (item.videoId) {
        return Number(item.videoId);
      }

      if (!item.mmsVid) {
        return 0;
      }

      const pageSize = 50;
      const maxPage = 10;
      let page = 1;
      let totalPage = 1;

      do {
        const result = await getVideoList(page, pageSize, 'ptime', 'desc');
        const list = (result && result.list) || [];

        const match = list.find((video) => {
          return video.mmsVid === item.mmsVid;
        });

        if (match && match.videoId) {
          return Number(match.videoId);
        }

        totalPage = (result && result.totalPage) || 1;
        page += 1;
      } while (page <= totalPage && page <= maxPage);

      return 0;
    },
    async removeItem(item) {
      let shopeeDeleteFailed = false;

      if (this.normalizeStatus(item) === 'done') {
        const videoId = await this.resolveShopeeVideoId(item);

        if (videoId) {
          const deleted = await deleteVideo(videoId);

          if (!deleted) {
            shopeeDeleteFailed = true;
          }
        } else {
          shopeeDeleteFailed = true;
        }
      }

      const removed = await apiShopeeVideoItemRemove(item._id);

      if (!removed) {
        this.$Message.error(this.$t('SHOPEE_VIDEO_DASH_SAVE_ERROR'));
        return;
      }

      const index = this.items.findIndex((row) => {
        return row._id === item._id;
      });

      if (index !== -1) {
        this.items.splice(index, 1);
      }

      const campaignIndex = this.campaigns.findIndex((campaign) => {
        return campaign._id === this.activeCampaignId;
      });

      if (campaignIndex !== -1) {
        const campaign = this.campaigns[campaignIndex];
        const nextTotal = Math.max(0, (campaign.totalItems || 0) - 1);
        this.campaigns.splice(campaignIndex, 1, { ...campaign, totalItems: nextTotal });
      }

      await this.refreshStats();

      if (shopeeDeleteFailed) {
        this.$Message.warning(this.$t('SHOPEE_VIDEO_DASH_DELETE_SHOPEE_FAIL'));
        return;
      }

      this.$Message.success(this.$t('SHOPEE_VIDEO_DASH_DELETE_SUCCESS'));
    },
  },
});
</script>

<style lang="scss" scoped>
.sv-dash {
  padding: 16px;

  &__toolbar {
    display: flex;
    justify-content: flex-end;
    gap: 4px;
    margin-bottom: 12px;
  }

  &__link {
    color: #2d8cf0;
  }

  &__stats {
    display: flex;
    gap: 12px;
    margin-bottom: 16px;
    flex-wrap: wrap;
  }

  &__body {
    display: flex;
    gap: 16px;
    align-items: flex-start;
  }

  &__side {
    width: 280px;
    flex-shrink: 0;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 4px 16px rgba(17, 24, 39, 0.06);
    padding: 16px;
  }

  &__side-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 12px;
  }

  &__side-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
  }

  &__side-title {
    font-size: 15px;
    font-weight: 600;
    color: #1f2329;
    margin: 0;
  }

  &__side-empty {
    font-size: 13px;
    color: #b0b4bb;
    padding: 12px 0;
  }

  &__main {
    flex: 1;
    min-width: 0;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 4px 16px rgba(17, 24, 39, 0.06);
    padding: 16px;
  }

  &__main-empty {
    text-align: center;
    color: #b0b4bb;
    font-size: 14px;
    padding: 48px 0;
  }

  &__filter {
    margin-bottom: 0;
  }

  &__mainbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
    flex-wrap: wrap;
  }

  &__publish-all {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  &__publish-prog {
    font-size: 12px;
    color: #8a8f99;
  }

  &__bulk.ivu-btn {
    margin-right: auto;
  }

  &__empty {
    text-align: center;
    padding: 60px 0;
    color: #b0b4bb;

    i {
      font-size: 42px;
    }

    p {
      margin-top: 10px;
      font-size: 14px;
    }
  }
}

.sv-stat {
  flex: 1;
  min-width: 130px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(17, 24, 39, 0.06);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;

  &__label {
    font-size: 13px;
    color: #8a8f99;
  }

  &__value {
    font-size: 24px;
    font-weight: 700;
    color: #1f2329;
  }

  &.is-done &__value {
    color: #19be6b;
  }

  &.is-error &__value {
    color: #ed4014;
  }

  &.is-pending &__value {
    color: #ff9900;
  }
}

.sv-campaigns {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 420px;
  overflow-y: auto;
}

.sv-campaign {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s ease;

  &:hover {
    background: #f4f5f7;
  }

  &:hover &__actions {
    opacity: 1;
  }

  &.is-active {
    background: rgba(45, 140, 240, 0.08);
  }

  &__info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }

  &__name {
    font-size: 14px;
    font-weight: 600;
    color: #1f2329;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  &__meta {
    font-size: 12px;
    color: #8a8f99;
  }

  &__actions {
    flex-shrink: 0;
    display: flex;
    gap: 2px;
    opacity: 0;
    transition: opacity 0.15s ease;
  }

  &.is-active &__actions {
    opacity: 1;
  }
}

.sv-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: calc(100vh - 280px);
  overflow-y: auto;
  padding-right: 4px;

  &__state {
    padding: 48px 0;
    text-align: center;
    color: #b0b4bb;
    font-size: 14px;

    p {
      margin: 8px 0 0;
    }
  }

  &__state-icon {
    font-size: 40px;
    color: #d4d7dd;
  }
}

.sv-card {
  position: relative;
  flex-shrink: 0;
  border: 1px solid #eef0f3;
  border-radius: 12px;
  background: #fff;
  overflow: hidden;
  transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: 4px;
    background: #c9ced6;
  }

  &.is-done::before {
    background: #19be6b;
  }

  &.is-error::before {
    background: #ed4014;
  }

  &.is-pending::before {
    background: #ff9900;
  }

  &:hover {
    border-color: #e0e3e8;
    box-shadow: 0 8px 22px rgba(17, 24, 39, 0.08);
    transform: translateY(-1px);
  }

  &__body {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 14px 16px 14px 18px;
  }

  &__main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  &__head {
    display: flex;
    align-items: flex-start;
    gap: 4px;
  }

  &__caption {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: #1f2329;
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  &__edit {
    flex-shrink: 0;
    opacity: 0.5;

    &:hover {
      opacity: 1;
    }
  }

  &__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }

  &__toggle {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: 12px;
    font-weight: 500;
    color: #2d8cf0;
    cursor: pointer;

    &:hover {
      color: #1c6dd0;
    }
  }

  &__err {
    font-size: 12px;
    color: #ed4014;
  }

  &__act {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    width: 88px;
  }

  &__post.ivu-btn {
    font-weight: 600;
  }

  &__del.ivu-btn {
    color: #8a8f99;

    &:hover,
    &:focus {
      color: #ed4014;
      background: #fdeceb;
    }
  }

  &__products {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 0 16px 14px 18px;
    border-top: 1px dashed #eef0f3;
    margin: 0 0 0 18px;
    padding-top: 12px;
  }
}

.sv-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  padding: 2px 10px;
  border-radius: 999px;
  line-height: 1.6;

  &__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
  }

  &.is-done {
    color: #18a058;
    background: #e8faf0;
  }

  &.is-error {
    color: #d03050;
    background: #fdecee;
  }

  &.is-pending {
    color: #d98500;
    background: #fff6e6;
  }

  &.is-archived {
    color: #8a8f99;
    background: #f1f2f4;
  }
}

.sv-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #8a8f99;

  i {
    font-size: 14px;
  }

  &--id {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    color: #6b7280;
    background: #f4f5f7;
    padding: 1px 8px;
    border-radius: 6px;
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease;

    &:hover {
      color: #2d8cf0;
      background: rgba(45, 140, 240, 0.1);
    }
  }
}

.sv-card__metrics {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  padding: 8px 12px;
  margin-top: 2px;
  background: #f8f9fb;
  border-radius: 8px;
}

.sv-metric {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 600;
  color: #515a6e;

  i {
    font-size: 16px;
    color: #9aa0aa;
  }

  &.is-sold {
    color: #ee4d2d;

    i {
      color: #ee4d2d;
    }
  }
}

.sv-card__synced {
  margin-left: auto;
  font-size: 11px;
  color: #b0b4bb;
}

.sv-card__sync.ivu-btn {
  color: #515a6e;

  &:hover {
    color: #2d8cf0;
    border-color: #2d8cf0;
  }
}

.sv-thumb {
  position: relative;
  width: 86px;
  height: 112px;
  border-radius: 8px;
  overflow: hidden;
  background: #1f2329;
  flex-shrink: 0;
  cursor: pointer;

  &:hover &__ph {
    background: rgba(0, 0, 0, 0.32);
  }

  &:hover &__play {
    transform: scale(1.12);
    opacity: 1;
  }

  &__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #1f2329;
    pointer-events: none;
  }

  &__ph {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.28));
    transition: background 0.18s ease;
  }

  &__play {
    color: #fff;
    font-size: 30px;
    opacity: 0.92;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
    transition: transform 0.18s ease, opacity 0.18s ease;
  }

  &__src {
    position: absolute;
    top: 4px;
    left: 4px;
    font-size: 10px;
    font-weight: 600;
    color: #fff;
    background: rgba(0, 0, 0, 0.6);
    padding: 1px 6px;
    border-radius: 4px;

    &.is-shopee {
      background: rgba(238, 77, 45, 0.9);
    }

    &.is-product {
      background: rgba(45, 140, 240, 0.9);
    }
  }

  &__dur {
    position: absolute;
    bottom: 4px;
    right: 4px;
    font-size: 10px;
    color: #fff;
    background: rgba(0, 0, 0, 0.7);
    padding: 1px 5px;
    border-radius: 4px;
  }
}

.sv-prod {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 260px;
  padding: 6px;
  border: 1px solid #eef0f3;
  border-radius: 8px;

  &__img {
    width: 40px;
    height: 40px;
    border-radius: 6px;
    object-fit: cover;
    flex-shrink: 0;
    background: #eef0f3;
  }

  &__info {
    min-width: 0;
    display: flex;
    flex-direction: column;
  }

  &__name {
    font-size: 12px;
    color: #2d2f33;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  &__price {
    font-size: 12px;
    color: #ee4d2d;
    font-weight: 600;
  }
}

.sv-preview-video {
  width: 100%;
  max-height: 70vh;
  display: block;
  background: #000;
  border-radius: 8px;
}

@media (max-width: 860px) {
  .sv-dash__body {
    flex-direction: column;
  }

  .sv-dash__side {
    width: 100%;
  }
}
</style>
