import { createPinia } from 'pinia'
import { __, _n, sprintf } from '@wordpress/i18n'
import { ref } from 'vue'
import { getI18n, l10nObj, sanitizeSubtitleHtml } from '@/helper'
import { useCollectionsStore } from '@/api'
import {
  notification,
} from 'ant-design-vue'
import { ICollectionPayload } from '@/types'
import { generatePaginationItems } from '@/utils/pagination'
import { attachEscHandler, detachEscHandler } from '../shared/escHandler'
import { refreshWishlistData } from '../shared/wishlistDataMethods'
import { fetchUsers } from '../shared/fetchUsers'

/**
 * Return `url` only when it is an `http`/`https` URL. Any other scheme
 * (`javascript:`, `data:`, `vbscript:`, …) is rejected so the lite plugin
 * never binds an untrusted scheme into `:href` or hands it to `window.open()`.
 */
function safeRegistryUrl(url: unknown): string | null {
  return typeof url === 'string' && /^https?:\/\//i.test(url) ? url : null
}

/**
 * Parse a MySQL DATETIME (UTC, "YYYY-MM-DD HH:MM:SS") or ISO-8601 string into
 * a Date. Returns null when the value is empty or not parseable so callers can
 * short-circuit without repeating the same guard.
 */
function parseMysqlDatetime(value: string | null | undefined): Date | null {
  if (!value) {
    return null
  }
  const isoLike = value.includes('T') ? value : value.replace(' ', 'T') + 'Z'
  const date = new Date(isoLike)
  return Number.isNaN(date.getTime()) ? null : date
}

// Plural-aware unit thresholds for relative date formatting. `_n()` defers
// plural-rule selection to the active locale, so locales with more than two
// plural forms (Polish, Russian, Arabic, …) get the correct phrase.
const RELATIVE_UNITS: { limit: number, divisor: number, format: (count: number) => string }[] = [
  {
    limit: 60,
    divisor: 1,
    // translators: %s: amount of seconds since the wishlist was created.
    format: (count) => sprintf(
      _n('%s second ago', '%s seconds ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: 3600,
    divisor: 60,
    // translators: %s: amount of minutes since the wishlist was created.
    format: (count) => sprintf(
      _n('%s minute ago', '%s minutes ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: 86400,
    divisor: 3600,
    // translators: %s: amount of hours since the wishlist was created.
    format: (count) => sprintf(
      _n('%s hour ago', '%s hours ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: 604800,
    divisor: 86400,
    // translators: %s: amount of days since the wishlist was created.
    format: (count) => sprintf(
      _n('%s day ago', '%s days ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: 2592000,
    divisor: 604800,
    // translators: %s: amount of weeks since the wishlist was created.
    format: (count) => sprintf(
      _n('%s week ago', '%s weeks ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: 31536000,
    divisor: 2592000,
    // translators: %s: amount of months since the wishlist was created.
    format: (count) => sprintf(
      _n('%s month ago', '%s months ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
  {
    limit: Infinity,
    divisor: 31536000,
    // translators: %s: amount of years since the wishlist was created.
    format: (count) => sprintf(
      _n('%s year ago', '%s years ago', count, 'saveto-wishlist-lite-for-woocommerce'),
      count,
    ),
  },
]

/**
 * Render a MySQL DATETIME (UTC) as a human "X ago" string.
 * Falls back to the localised date string if the value is missing or invalid.
 */
function formatRelativeDate(value: string | null | undefined): string {
  const date = parseMysqlDatetime(value)
  if (!date) {
    return ''
  }
  const seconds = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1000))
  if (seconds < 5) {
    return getI18n('just_now', __('just now', 'saveto-wishlist-lite-for-woocommerce'))
  }
  for (const unit of RELATIVE_UNITS) {
    if (seconds < unit.limit) {
      const count = Math.max(1, Math.floor(seconds / unit.divisor))
      return unit.format(count)
    }
  }
  return ''
}

function formatAbsoluteDate(value: string | null | undefined): string {
  const date = parseMysqlDatetime(value)
  if (!date) {
    return ''
  }
  return date.toLocaleString()
}

const pinia = createPinia()

const { getWishlists, deleteCollection, saveCollection } = useCollectionsStore(pinia)

const loadedObject = l10nObj()
const wishlistOptions = loadedObject.wishlistOptions
const isLoggedIn = loadedObject.isLoggedIn
const wishlistUrl = loadedObject.wishlistUrl
const proDependencies = loadedObject.proDependencies || {}
const activePro = proDependencies?.activePro || false
const registryActive = !!proDependencies?.registryActive
const wpRoles = proDependencies?.wpRoles || {}

const disablePublicWishlists = !!proDependencies?.disablePublicWishlists
const publicWishlistsTitle = proDependencies?.publicWishlistsTitle || getI18n('public_wishlists_title', __('Public Wishlists', 'saveto-wishlist-lite-for-woocommerce'))
const publicWishlistsDescription = proDependencies?.publicWishlistsDescription || getI18n('public_wishlists_subtitle', __('Browse publicly shared wishlists from other users.', 'saveto-wishlist-lite-for-woocommerce'))

// Translatable strings.
const wishlistTitle = getI18n('wishlist_title', wishlistOptions.title)
const wishlistSubtitle = getI18n('wishlist_subtitle', wishlistOptions.description)
const searchPlaceholder = getI18n('search_placeholder', __('Search for anything...', 'saveto-wishlist-lite-for-woocommerce'))
const searchLabel = getI18n('search_label', __('Search', 'saveto-wishlist-lite-for-woocommerce'))
const clearSearch = getI18n('clear_search', __('Clear search', 'saveto-wishlist-lite-for-woocommerce'))
const tableInfoString = getI18n('table_info', __('Showing %1$s-%2$s of %3$s items', 'saveto-wishlist-lite-for-woocommerce'))
const emptyTitle = getI18n('empty_title', __('No wishlists found', 'saveto-wishlist-lite-for-woocommerce'))
const emptyDescription = getI18n('empty_description', __('Create your first wishlist to get started.', 'saveto-wishlist-lite-for-woocommerce'))
const loginToView = getI18n('login_to_view', __('Login to view your wishlists.', 'saveto-wishlist-lite-for-woocommerce'))
const newWishlist = getI18n('new_wishlist', __('New Wishlist', 'saveto-wishlist-lite-for-woocommerce'))
const addWishlist = getI18n('add_wishlist', __('Add Wishlist', 'saveto-wishlist-lite-for-woocommerce'))
const wishlistName = getI18n('wishlist_name', __('Wishlist Name', 'saveto-wishlist-lite-for-woocommerce'))
const wishlistDescription = getI18n('wishlist_description', __('Wishlist Description', 'saveto-wishlist-lite-for-woocommerce'))
const cancel = getI18n('cancel', __('Cancel', 'saveto-wishlist-lite-for-woocommerce'))
const create = getI18n('create', __('Create', 'saveto-wishlist-lite-for-woocommerce'))
const creating = getI18n('creating', __('Creating...', 'saveto-wishlist-lite-for-woocommerce'))
const editWishlist = getI18n('edit_wishlist', __('Edit Wishlist', 'saveto-wishlist-lite-for-woocommerce'))
const isDefault = getI18n('is_default', __('Is Default', 'saveto-wishlist-lite-for-woocommerce'))
const update = getI18n('update', __('Update', 'saveto-wishlist-lite-for-woocommerce'))
const updating = getI18n('updating', __('Updating...', 'saveto-wishlist-lite-for-woocommerce'))
const publish = getI18n('publish', __('Publish', 'saveto-wishlist-lite-for-woocommerce'))
const draft = getI18n('draft', __('Draft', 'saveto-wishlist-lite-for-woocommerce'))
const defaultText = getI18n('default', __('Default', 'saveto-wishlist-lite-for-woocommerce'))
const isPublic = getI18n('is_public', __('Is Public', 'saveto-wishlist-lite-for-woocommerce'))
const loading = getI18n('loading', __('Loading...', 'saveto-wishlist-lite-for-woocommerce'))
const publicText = getI18n('public', __('Public', 'saveto-wishlist-lite-for-woocommerce'))
const publicTooltip = getI18n('public_tooltip', __('Anyone with the link can view this wishlist.', 'saveto-wishlist-lite-for-woocommerce'))
const shareText = getI18n('share', __('Share', 'saveto-wishlist-lite-for-woocommerce'))
const shareByEmail = getI18n('share_by_email', __('Share by Email', 'saveto-wishlist-lite-for-woocommerce'))
const enterEmail = getI18n('enter_email', __('Enter email address', 'saveto-wishlist-lite-for-woocommerce'))
const addText = getI18n('add', __('Add', 'saveto-wishlist-lite-for-woocommerce'))
const shareWithUsers = getI18n('share_with_users', __('Share with Users', 'saveto-wishlist-lite-for-woocommerce'))
const restrictionsText = getI18n('restrictions', __('Restrictions', 'saveto-wishlist-lite-for-woocommerce'))
const restrictByRoles = getI18n('restrict_by_roles', __('Restrict by Roles', 'saveto-wishlist-lite-for-woocommerce'))
const shareLink = getI18n('share_link', __('Share Link', 'saveto-wishlist-lite-for-woocommerce'))
const clearSelect = getI18n('clear_select', __('Clear', 'saveto-wishlist-lite-for-woocommerce'))
const searchRoles = getI18n('search_roles', __('Search roles...', 'saveto-wishlist-lite-for-woocommerce'))
const searchUsers = getI18n('search_users', __('Search users...', 'saveto-wishlist-lite-for-woocommerce'))
const whoCanEdit = getI18n('who_can_edit', __('Who Can Edit', 'saveto-wishlist-lite-for-woocommerce'))
const confirmDeleteTitle = getI18n('confirm_delete_wishlist_title', __('Delete Wishlist', 'saveto-wishlist-lite-for-woocommerce'))
const confirmDeleteMessage = getI18n('confirm_delete_wishlist_message', __('Are you sure you want to delete this wishlist? This action cannot be undone.', 'saveto-wishlist-lite-for-woocommerce'))
const cannotDeleteLastMessage = getI18n('cannot_delete_last_wishlist', __('This wishlist cannot be deleted because it is your only wishlist and would be recreated automatically.', 'saveto-wishlist-lite-for-woocommerce'))
const convertToRegistry = getI18n('convert_to_registry', __('Convert to Registry', 'saveto-wishlist-lite-for-woocommerce'))
const viewRegistry = getI18n('view_registry', __('View Registry', 'saveto-wishlist-lite-for-woocommerce'))
const registryBadge = getI18n('registry_badge', __('Registry', 'saveto-wishlist-lite-for-woocommerce'))

const table = {
  name: getI18n('column_name', __('Name', 'saveto-wishlist-lite-for-woocommerce')),
  status: getI18n('column_status', __('Status', 'saveto-wishlist-lite-for-woocommerce')),
  author: getI18n('column_author', __('Author', 'saveto-wishlist-lite-for-woocommerce')),
  date_added: getI18n('column_date_added', __('Date Added', 'saveto-wishlist-lite-for-woocommerce')),
  actions: getI18n('column_actions', __('Actions', 'saveto-wishlist-lite-for-woocommerce')),
  show: getI18n('show', __('Show', 'saveto-wishlist-lite-for-woocommerce')),
  previous: getI18n('previous', __('Previous', 'saveto-wishlist-lite-for-woocommerce')),
  next: getI18n('next', __('Next', 'saveto-wishlist-lite-for-woocommerce')),
  delete: getI18n('delete', __('Delete', 'saveto-wishlist-lite-for-woocommerce')),
  manage: getI18n('manage', __('Manage', 'saveto-wishlist-lite-for-woocommerce')),
  view: getI18n('view', __('View', 'saveto-wishlist-lite-for-woocommerce')),
}

const wishlist = ref<any>({
  title: wishlistTitle,
  subtitle: wishlistSubtitle,
  isLoggedIn: isLoggedIn,
  searchPlaceholder: searchPlaceholder,
  searchLabel: searchLabel,
  clearSearch: clearSearch,
  userRole: loadedObject.user_role,
  table: table,
  empty: {
    title: emptyTitle,
    description: emptyDescription,
  },
  loginToView: loginToView,
  pageUrls: loadedObject.pageUrls,
  newWishlist: newWishlist,
  addWishlist: addWishlist,
  cancel: cancel,
  create: create,
  wishlistName: wishlistName,
  wishlistDescription: wishlistDescription,
  creating: creating,
  editWishlist: editWishlist,
  isDefault: isDefault,
  update: update,
  updating: updating,
  publish: publish,
  draft: draft,
  default: defaultText,
  isPublic: isPublic,
  loading: loading,
  allowMultipleWishlists: wishlistOptions.allowMultipleWishlists,
  public: publicText,
  publicTooltip: publicTooltip,
  wishlistUrl: wishlistUrl,
  sanitizeSubtitleHtml: sanitizeSubtitleHtml,
  getI18n: getI18n,
  activePro: activePro,
  share: shareText,
  shareByEmail: shareByEmail,
  enterEmail: enterEmail,
  add: addText,
  shareWithUsers: shareWithUsers,
  restrictions: restrictionsText,
  restrictByRoles: restrictByRoles,
  shareLink: shareLink,
  clearSelect: clearSelect,
  searchRoles: searchRoles,
  searchUsers: searchUsers,
  whoCanEdit: whoCanEdit,
  disablePublicWishlists: disablePublicWishlists,
  publicWishlistsTitle: publicWishlistsTitle,
  publicWishlistsDescription: publicWishlistsDescription,
  confirmDeleteTitle: confirmDeleteTitle,
  confirmDeleteMessage: confirmDeleteMessage,
  convertToRegistry: convertToRegistry,
  viewRegistry: viewRegistry,
  registryActive: registryActive,
  registry: registryBadge,
  safeRegistryUrl: safeRegistryUrl,
  formatRelativeDate: formatRelativeDate,
  formatAbsoluteDate: formatAbsoluteDate,
  pageStyles: loadedObject.pageStyles || {},
})

const getWishlist = async (params: any) => {
  let lists: any[] = []
  let pagination = {
    current: 1,
    pageSize: 10,
    total: 0,
    totalPages: 0,
  }

  await getWishlists({
    page: params.page,
    posts_per_page: params.posts_per_page,
    search: params.search,
    status: params.status,
    user_id: params.user_id,
    sort_column: params.sort_column,
    sort_order: params.sort_order,
  }).then((response: any) => {

    // Pagination
    pagination = {
      ...pagination,
      total: response.total,
      totalPages: Math.ceil(response.total / params.posts_per_page),
    }

    // Table data
    lists = response.data.map((item: any) => ({
      ...item,
      status: item.status,
    }))

  }).catch((e: any) => {
    if (e.error?.message) {
      notification.error({
        message: getI18n('error', __('Error', 'saveto-wishlist-lite-for-woocommerce')),
        description: e.error?.message,
        class: 'wishlist-lists-error-notification',
      })
    }
  })

  return {
    lists,
    pagination,
  }
}

const getPublicWishlists = async (params: any) => {
  let lists: any[] = []
  let pagination = {
    current: 1,
    pageSize: 10,
    total: 0,
    totalPages: 0,
  }

  await getWishlists({
    page: params.page,
    posts_per_page: params.posts_per_page,
    search: params.search,
    status: params.status,
    is_public: 1,
    sort_column: params.sort_column,
    sort_order: params.sort_order,
  }).then((response: any) => {

    // Pagination
    pagination = {
      ...pagination,
      total: response.total,
      totalPages: Math.ceil(response.total / params.posts_per_page),
    }

    // Table data
    lists = response.data.map((item: any) => ({
      ...item,
      status: item.status,
    }))

  }).catch((e: any) => {
    if (e.error?.message) {
      notification.error({
        message: getI18n('error', __('Error', 'saveto-wishlist-lite-for-woocommerce')),
        description: e.error?.message,
        class: 'wishlist-lists-error-notification',
      })
    }
  })

  return {
    lists,
    pagination,
  }
}

const wishlistMounted = () => {
  return {
    wishlist,
    lists: [] as any[],
    fetchingItems: false,
    search: '',
    status: '',
    user_id: loadedObject.user_id,
    sortColumn: 'id',
    sortOrder: 'DESC',
    addingWishlist: false,
    addWishlistPopup: false,
    addWishlist: {
      name: '',
      description: '',
      status: 'publish',
      is_default: false,
      is_public: false,
      emails: [] as string[],
      user_ids: [] as number[],
      allowed_roles: [] as string[],
      allowed_edit_emails: [] as string[],
      user_id: '',
    },
    addWishlistEmailInput: '',
    addWishlistSelectedUsers: [] as any[],
    addWishlistUserOptions: [] as any[],
    addWishlistUserSearch: '',
    addWishlistFilteredUserOptions: [] as any[],
    addWishlistSelectedRoles: [] as any[],
    addWishlistRoleOptions: [] as any[],
    addWishlistRoleSearch: '',
    addWishlistFilteredRoleOptions: [] as any[],
    addWishlistEditEmailInput: '',
    deletingItemId: '',
    deletingItem: false,
    deleteConfirmPopup: false,
    deleteConfirmId: '' as string,
    convertCollectionId: 0 as number,
    _escHandler: null as null | ((e: KeyboardEvent) => void),
    editingWishlist: false,
    editWishlistPopup: false,
    editWishlist: {
      id: '',
      name: '',
      description: '',
      status: 'publish',
      is_default: false,
      is_public: false,
      url_code: '',
      emails: [] as string[],
      user_ids: [] as number[],
      allowed_roles: [] as string[],
      allowed_edit_emails: [] as string[],
      user_id: '',
    },
    editWishlistEmailInput: '',
    editWishlistSelectedUsers: [] as any[],
    editWishlistUserOptions: [] as any[],
    editWishlistUserSearch: '',
    editWishlistFilteredUserOptions: [] as any[],
    editWishlistSelectedRoles: [] as any[],
    editWishlistRoleOptions: [] as any[],
    editWishlistRoleSearch: '',
    editWishlistFilteredRoleOptions: [] as any[],
    editWishlistEditEmailInput: '',
    pagination: {
      current: 1,
      pageSize: 10,
      total: 0,
      totalPages: 0,
    },
    tableInfo: '',
    users: [] as any[],
    copied: false,
    copiedLabel: getI18n('copied', __('Copied', 'saveto-wishlist-lite-for-woocommerce')),
    copyLabel: getI18n('copy', __('Copy', 'saveto-wishlist-lite-for-woocommerce')),
    publicLists: [] as any[],
    fetchingPublicItems: false,
    publicSearch: '',
    publicSortColumn: 'id',
    publicSortOrder: 'DESC',
    publicPagination: {
      current: 1,
      pageSize: 10,
      total: 0,
      totalPages: 0,
    },
    publicTableInfo: '',
    get userList() {
      // Check if user is logged in.
      if (!isLoggedIn) {
        return []
      }

      fetchUsers().then((users: any[]) => {
        this.users = users
      })

      return this.users
    },
    getUserName(id: string) {
      const userId = parseInt(id)
      return this.users.find((user: any) => user.id === userId)?.name
    },
    get wishlistData() {
      // Check if user is logged in.
      if (!isLoggedIn) {
        return []
      }

      // If user is not admin, set status to publish.
      if (wishlist.value.userRole !== 'admin') {
        this.status = ''
      }

      const params = {
        page: this.pagination.current,
        posts_per_page: this.pagination.pageSize,
        search: this.search,
        status: this.status,
        user_id: this.user_id,
        sort_column: this.sortColumn,
        sort_order: this.sortOrder,
      }

      this.fetchingItems = true

      getWishlist(params).then((res: any) => {
        this.lists = res.lists
        this.pagination.total = res.pagination.total
        this.pagination.totalPages = res.pagination.totalPages
        this.fetchingItems = false
        this.updatePagination()
      })

      return {
        lists: this.lists,
        pagination: this.pagination,
      }
    },
    onSearch() {
      this.wishlistData
    },
    clearSearch() {
      this.search = ''
      this.wishlistData
    },
    get publicWishlistData() {
      // Check if user is logged in.
      if (!isLoggedIn) {
        return []
      }

      const params = {
        page: this.publicPagination.current,
        posts_per_page: this.publicPagination.pageSize,
        search: this.publicSearch,
        status: '',
        sort_column: this.publicSortColumn,
        sort_order: this.publicSortOrder,
      }

      this.fetchingPublicItems = true

      getPublicWishlists(params).then((res: any) => {
        this.publicLists = res.lists
        this.publicPagination.total = res.pagination.total
        this.publicPagination.totalPages = res.pagination.totalPages
        this.fetchingPublicItems = false
        this.updatePublicPagination()
      })

      return {
        lists: this.publicLists,
        pagination: this.publicPagination,
      }
    },
    onPublicSearch() {
      this.publicWishlistData
    },
    clearPublicSearch() {
      this.publicSearch = ''
      this.publicWishlistData
    },
    handlePublicSort(column: string) {
      this.publicSortColumn = column
      this.publicSortOrder = this.publicSortOrder === 'asc' ? 'desc' : 'asc'
      this.publicWishlistData
    },
    updatePublicTableInfo() {
      const startIndex = (this.publicPagination.current - 1) * this.publicPagination.pageSize + 1
      const endIndex = Math.min(this.publicPagination.current * this.publicPagination.pageSize, this.publicPagination.total)

      this.publicTableInfo = tableInfoString.replace('%1$s', startIndex.toString()).replace('%2$s', endIndex.toString()).replace('%3$s', this.publicPagination.total.toString())
    },
    handlePublicItemsPerPageChange(event: any) {
      this.publicPagination.pageSize = parseInt(event.target.value)
      this.publicWishlistData
    },
    handlePublicPagination(direction: string) {
      if (direction === 'prev' && this.publicPagination.current > 1) {
        this.publicPagination.current--
      } else if (direction === 'next' && this.publicPagination.current < this.publicPagination.totalPages) {
        this.publicPagination.current++
      }

      this.publicWishlistData
    },
    handlePublicPaginationNumber(page: number) {
      this.publicPagination.current = page
      this.publicWishlistData
    },
    updatePublicPagination() {
      this.updatePublicTableInfo()
    },
    get publicPaginationItems() {
      const current = this.publicPagination.current
      const totalPages = this.publicPagination.totalPages

      return generatePaginationItems(current, totalPages)
    },
    handleSort(column: string) {
      // First click on a new column should land on newest-first; only toggle
      // when the user re-clicks the already-active column.
      if (this.sortColumn === column) {
        this.sortOrder = this.sortOrder === 'ASC' ? 'DESC' : 'ASC'
      } else {
        this.sortColumn = column
        this.sortOrder = 'DESC'
      }
      this.wishlistData
    },
    updateTableInfo() {
      const startIndex = (this.pagination.current - 1) * this.pagination.pageSize + 1
      const endIndex = Math.min(this.pagination.current * this.pagination.pageSize, this.pagination.total)

      this.tableInfo = tableInfoString.replace('%1$s', startIndex.toString()).replace('%2$s', endIndex.toString()).replace('%3$s', this.pagination.total.toString())
    },
    handleItemsPerPageChange(event: any) {
      this.pagination.pageSize = parseInt(event.target.value)
      this.wishlistData
    },
    handlePagination(direction: string) {
      if (direction === 'prev' && this.pagination.current > 1) {
        this.pagination.current--
      } else if (direction === 'next' && this.pagination.current < this.pagination.total) {
        this.pagination.current++
      }

      this.wishlistData
    },
    handlePaginationNumber(page: number) {
      this.pagination.current = page
      this.wishlistData
    },
    updatePagination() {
      this.updateTableInfo()
    },
    get paginationItems() {
      const current = this.pagination.current
      const totalPages = this.pagination.totalPages

      return generatePaginationItems(current, totalPages)
    },
    handleDelete(id: string) {
      this.deleteConfirmId = id
      this.deleteConfirmPopup = true
      this._escHandler = attachEscHandler(() => this.handleDeleteCancel())
    },
    handleDeleteConfirm() {
      const id = this.deleteConfirmId
      this.deleteConfirmPopup = false
      this.deleteConfirmId = ''
      this._escHandler = detachEscHandler(this._escHandler)
      this.deletingItemId = id
      this.deletingItem = true
      deleteCollection(id).then((res: any) => {
        this.deletingItem = false
        this.deletingItemId = ''

        if (Array.isArray(res?.skipped) && res.skipped.length > 0) {
          notification.error({
            message: getI18n('cannot_delete_last_wishlist_title', __('Wishlist cannot be deleted', 'saveto-wishlist-lite-for-woocommerce')),
            description: res?.message || cannotDeleteLastMessage,
            class: 'wishlist-cannot-delete-last-notification',
          })
        }

        this.wishlistData
      }).catch((e: any) => {
        this.deletingItem = false
        this.deletingItemId = ''
      })
    },
    isLastUserWishlist(item: any): boolean {
      if (!isLoggedIn) {
        return false
      }
      // The recreation only fires for the owner, so only disable the button
      // on the current user's own row. Admins acting on another user's row
      // are caught by the backend guard.
      if (parseInt(item.user_id) !== parseInt(this.user_id)) {
        return false
      }
      // A search-narrowed view of a multi-wishlist user can look like a
      // single-wishlist user. Skip the disable in that case — pagination.total
      // is only authoritative when no filter is active.
      if (this.search) {
        return false
      }
      return this.pagination.total === 1
    },
    handleDeleteCancel() {
      this.deleteConfirmPopup = false
      this.deleteConfirmId = ''
      this._escHandler = detachEscHandler(this._escHandler)
    },
    handleOpenConvertRegistry(id: string) {
      this.convertCollectionId = parseInt(id, 10) || 0
    },
    handleCloseConvertRegistry() {
      this.convertCollectionId = 0
    },
    refreshWishlist() {
      return refreshWishlistData(this)
    },
    handleRegistryConverted(event: CustomEvent) {
      this.convertCollectionId = 0
      // Web component emits ['public_url'] inside detail; refresh table so the
      // converted row picks up its registry annotation and the icon hides.
      this.refreshWishlist()
      const detail = event?.detail
      const rawUrl = Array.isArray(detail) ? detail[0] : detail
      const url = safeRegistryUrl(rawUrl)
      if (url) {
        window.open(url, '_blank', 'noopener')
      }
    },
    handleAddWishlistPopup() {
      this.addWishlistPopup = true
      // Initialize role options from wpRoles
      this.addWishlistRoleOptions = Object.entries(wpRoles).map(([key, value]) => ({
        label: value,
        value: key,
      }))
      this.addWishlistSelectedRoles = []
      this.addWishlistRoleSearch = ''
      this.addWishlistFilteredRoleOptions = []
      // Initialize user options
      if (this.users.length === 0) {
        fetchUsers().then((users: any[]) => {
          this.users = users
          this.addWishlistUserOptions = users.map((user: any) => ({
            label: user.name,
            value: user.id,
          }))
          this.addWishlistSelectedUsers = []
          this.addWishlistUserSearch = ''
          this.addWishlistFilteredUserOptions = []
          this.addWishlistEditEmailInput = ''
        })
      } else {
        this.addWishlistUserOptions = this.users.map((user: any) => ({
          label: user.name,
          value: user.id,
        }))
        this.addWishlistSelectedUsers = []
        this.addWishlistUserSearch = ''
        this.addWishlistFilteredUserOptions = []
        this.addWishlistEditEmailInput = ''
      }
    },
    handleCloseAddWishlistPopup() {
      this.addWishlistPopup = false
      this.addWishlist.name = ''
      this.addWishlist.description = ''
      this.addWishlist.emails = []
      this.addWishlist.user_ids = []
      this.addWishlist.allowed_roles = []
      this.addWishlist.allowed_edit_emails = []
      this.addWishlistEmailInput = ''
      this.addWishlistSelectedUsers = []
      this.addWishlistSelectedRoles = []
      this.addWishlistEditEmailInput = ''
      this.addWishlistUserSearch = ''
      this.addWishlistFilteredUserOptions = []
      this.addWishlistRoleSearch = ''
      this.addWishlistFilteredRoleOptions = []
    },
    handleAddEmail(context: 'add' | 'edit' = 'add') {
      const emailInput = context === 'add' ? this.addWishlistEmailInput : this.editWishlistEmailInput
      const email = emailInput.trim()
      if (email && email.includes('@')) {
        if (context === 'add') {
          if (!this.addWishlist.emails.includes(email)) {
            this.addWishlist.emails.push(email)
            this.addWishlistEmailInput = ''
          }
        } else {
          if (!this.editWishlist.emails.includes(email)) {
            this.editWishlist.emails.push(email)
            this.editWishlistEmailInput = ''
          }
        }
      }
    },
    handleRemoveEmail(email: string, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.emails = this.addWishlist.emails.filter((e: string) => e !== email)
      } else {
        this.editWishlist.emails = this.editWishlist.emails.filter((e: string) => e !== email)
      }
    },
    handleUserSelectionChange(userIds: number[], context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.user_ids = userIds
      } else {
        this.editWishlist.user_ids = userIds
      }
    },
    handleRoleSelectionChange(roles: string[], context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.allowed_roles = roles
      } else {
        this.editWishlist.allowed_roles = roles
      }
    },
    handleClearUsers(context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.user_ids = []
        this.addWishlistSelectedUsers = []
        this.addWishlistUserSearch = ''
        this.addWishlistFilteredUserOptions = []
      } else {
        this.editWishlist.user_ids = []
        this.editWishlistSelectedUsers = []
        this.editWishlistUserSearch = ''
        this.editWishlistFilteredUserOptions = []
      }
    },
    handleClearRoles(context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.allowed_roles = []
        this.addWishlistSelectedRoles = []
        this.addWishlistRoleSearch = ''
        this.addWishlistFilteredRoleOptions = []
      } else {
        this.editWishlist.allowed_roles = []
        this.editWishlistSelectedRoles = []
        this.editWishlistRoleSearch = ''
        this.editWishlistFilteredRoleOptions = []
      }
    },
    filterUsers(query: string, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlistUserSearch = query
        if (!query || query.trim() === '') {
          this.addWishlistFilteredUserOptions = []
          return
        }
        const lowerQuery = query.toLowerCase().trim()
        this.addWishlistFilteredUserOptions = this.addWishlistUserOptions.filter((user: any) =>
          user.label.toLowerCase().includes(lowerQuery) && !this.addWishlistSelectedUsers.some((selected: any) => selected.value === user.value)
        )
      } else {
        this.editWishlistUserSearch = query
        if (!query || query.trim() === '') {
          this.editWishlistFilteredUserOptions = []
          return
        }
        const lowerQuery = query.toLowerCase().trim()
        this.editWishlistFilteredUserOptions = this.editWishlistUserOptions.filter((user: any) =>
          user.label.toLowerCase().includes(lowerQuery) && !this.editWishlistSelectedUsers.some((selected: any) => selected.value === user.value)
        )
      }
    },
    selectUser(user: any, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        if (!this.addWishlistSelectedUsers.some((selected: any) => selected.value === user.value)) {
          this.addWishlistSelectedUsers.push(user)
          this.addWishlist.user_ids = this.addWishlistSelectedUsers.map((u: any) => u.value)
          this.addWishlistUserSearch = ''
          this.addWishlistFilteredUserOptions = []
        }
      } else {
        if (!this.editWishlistSelectedUsers.some((selected: any) => selected.value === user.value)) {
          this.editWishlistSelectedUsers.push(user)
          this.editWishlist.user_ids = this.editWishlistSelectedUsers.map((u: any) => u.value)
          this.editWishlistUserSearch = ''
          this.editWishlistFilteredUserOptions = []
        }
      }
    },
    removeUser(userId: number, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlistSelectedUsers = this.addWishlistSelectedUsers.filter((user: any) => user.value !== userId)
        this.addWishlist.user_ids = this.addWishlistSelectedUsers.map((u: any) => u.value)
      } else {
        this.editWishlistSelectedUsers = this.editWishlistSelectedUsers.filter((user: any) => user.value !== userId)
        this.editWishlist.user_ids = this.editWishlistSelectedUsers.map((u: any) => u.value)
      }
    },
    filterRoles(query: string, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlistRoleSearch = query
        if (!query || query.trim() === '') {
          this.addWishlistFilteredRoleOptions = []
          return
        }
        const lowerQuery = query.toLowerCase().trim()
        this.addWishlistFilteredRoleOptions = this.addWishlistRoleOptions.filter((role: any) =>
          role.label.toLowerCase().includes(lowerQuery) && !this.addWishlistSelectedRoles.some((selected: any) => selected.value === role.value)
        )
      } else {
        this.editWishlistRoleSearch = query
        if (!query || query.trim() === '') {
          this.editWishlistFilteredRoleOptions = []
          return
        }
        const lowerQuery = query.toLowerCase().trim()
        this.editWishlistFilteredRoleOptions = this.editWishlistRoleOptions.filter((role: any) =>
          role.label.toLowerCase().includes(lowerQuery) && !this.editWishlistSelectedRoles.some((selected: any) => selected.value === role.value)
        )
      }
    },
    selectRole(role: any, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        if (!this.addWishlistSelectedRoles.some((selected: any) => selected.value === role.value)) {
          this.addWishlistSelectedRoles.push(role)
          this.addWishlist.allowed_roles = this.addWishlistSelectedRoles.map((r: any) => r.value)
          this.addWishlistRoleSearch = ''
          this.addWishlistFilteredRoleOptions = []
        }
      } else {
        if (!this.editWishlistSelectedRoles.some((selected: any) => selected.value === role.value)) {
          this.editWishlistSelectedRoles.push(role)
          this.editWishlist.allowed_roles = this.editWishlistSelectedRoles.map((r: any) => r.value)
          this.editWishlistRoleSearch = ''
          this.editWishlistFilteredRoleOptions = []
        }
      }
    },
    removeRole(roleValue: string, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlistSelectedRoles = this.addWishlistSelectedRoles.filter((role: any) => role.value !== roleValue)
        this.addWishlist.allowed_roles = this.addWishlistSelectedRoles.map((r: any) => r.value)
      } else {
        this.editWishlistSelectedRoles = this.editWishlistSelectedRoles.filter((role: any) => role.value !== roleValue)
        this.editWishlist.allowed_roles = this.editWishlistSelectedRoles.map((r: any) => r.value)
      }
    },
    handleAddEditEmail(context: 'add' | 'edit' = 'add') {
      const emailInput = context === 'add' ? this.addWishlistEditEmailInput : this.editWishlistEditEmailInput
      const emailsArray = context === 'add' ? this.addWishlist.allowed_edit_emails : this.editWishlist.allowed_edit_emails

      const email = emailInput.trim()
      if (email && email.includes('@')) {
        if (context === 'add') {
          if (!this.addWishlist.allowed_edit_emails.includes(email)) {
            this.addWishlist.allowed_edit_emails.push(email)
            this.addWishlistEditEmailInput = ''
          }
        } else {
          if (!this.editWishlist.allowed_edit_emails.includes(email)) {
            this.editWishlist.allowed_edit_emails.push(email)
            this.editWishlistEditEmailInput = ''
          }
        }
      }
    },
    handleRemoveEditEmail(email: string, context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.allowed_edit_emails = this.addWishlist.allowed_edit_emails.filter((e: string) => e !== email)
      } else {
        this.editWishlist.allowed_edit_emails = this.editWishlist.allowed_edit_emails.filter((e: string) => e !== email)
      }
    },
    handleClearEditUsers(context: 'add' | 'edit' = 'add') {
      if (context === 'add') {
        this.addWishlist.allowed_edit_emails = []
        this.addWishlistEditEmailInput = ''
      } else {
        this.editWishlist.allowed_edit_emails = []
        this.editWishlistEditEmailInput = ''
      }
    },
    handleCreateWishlist() {
      const isDefault = this.addWishlist.status === 'publish' ? this.addWishlist.is_default : false
      const data = {
        action: 'add_wishlist',
        id: 0,
        name: this.addWishlist.name,
        description: this.addWishlist.description,
        status: this.addWishlist.status,
        is_default: isDefault,
        is_public: this.addWishlist.is_public,
        emails: this.addWishlist.emails,
        user_ids: this.addWishlist.user_ids,
        allowed_roles: this.addWishlist.allowed_roles,
        allowed_edit_emails: this.addWishlist.allowed_edit_emails,
      }

      this.addingWishlist = true
      saveCollection(data as any).then((res: any) => {
        notification.success({
          message: getI18n('success', __('Success', 'saveto-wishlist-lite-for-woocommerce')),
          description: res.message,
          class: 'wishlist-lists-success-notification',
        })

        this.addWishlistPopup = false
        this.addWishlist.name = ''
        this.addWishlist.description = ''
        this.addingWishlist = false
        this.wishlistData
      }).catch((e: any) => {
        notification.error({
          message: getI18n('error', __('Error', 'saveto-wishlist-lite-for-woocommerce')),
          description: getI18n('error_message', __('Failed to create wishlist.', 'saveto-wishlist-lite-for-woocommerce')),
          class: 'wishlist-lists-error-notification',
        })

        this.addWishlistPopup = false
        this.addWishlist.name = ''
        this.addWishlist.description = ''
        this.addingWishlist = false
      })
    },
    handleEditWishlistPopup(id: string) {
      const wishlist = this.lists.find((item: any) => item.id === id)

      // Without this guard, a stale row id (e.g. after a refresh races the
      // click) crashes the popup with "Cannot read properties of undefined".
      // Warn so genuine id-mismatch bugs surface instead of failing silently.
      if (!wishlist) {
        console.warn('[saveto-wishlist] handleEditWishlistPopup: no wishlist matched id', id)
        return
      }

      this.editWishlistPopup = true
      this.editWishlist = {
        id: wishlist.id,
        name: wishlist.name,
        description: wishlist.description,
        status: wishlist.status,
        is_default: wishlist.is_default === '1' ? true : false,
        is_public: wishlist.is_public === '1' ? true : false,
        url_code: wishlist.url_code,
        emails: wishlist.emails || [],
        user_ids: wishlist.user_ids || [],
        allowed_roles: wishlist.allowed_roles || [],
        allowed_edit_emails: wishlist.allowed_edit_emails || [],
        user_id: wishlist.user_id || '',
      }

      // Initialize role options from wpRoles
      this.editWishlistRoleOptions = Object.entries(wpRoles).map(([key, value]) => ({
        label: value,
        value: key,
      }))

      // Initialize selected roles - map role values to role objects
      this.editWishlistSelectedRoles = (this.editWishlist.allowed_roles || []).map((roleValue: string) =>
        this.editWishlistRoleOptions.find((role: any) => role.value === roleValue)
      ).filter((role: any) => role !== undefined)
      this.editWishlistRoleSearch = ''
      this.editWishlistFilteredRoleOptions = []

      // Initialize user options and selected users
      if (this.users.length === 0) {
        fetchUsers().then((users: any[]) => {
          this.users = users
          this.editWishlistUserOptions = users.map((user: any) => ({
            label: user.name,
            value: user.id,
          }))
          this.editWishlistSelectedUsers = (Array.isArray(this.editWishlist.user_ids) ? this.editWishlist.user_ids : []).map((userId: number) =>
            this.editWishlistUserOptions.find((user: any) => user.value === userId)
          ).filter((user: any) => user !== undefined)
          this.editWishlistUserSearch = ''
          this.editWishlistFilteredUserOptions = []
          this.editWishlistEditEmailInput = ''
        })
      } else {
        this.editWishlistUserOptions = this.users.map((user: any) => ({
          label: user.name,
          value: user.id,
        }))
        this.editWishlistSelectedUsers = (Array.isArray(this.editWishlist.user_ids) ? this.editWishlist.user_ids : []).map((userId: number) =>
          this.editWishlistUserOptions.find((user: any) => user.value === userId)
        ).filter((user: any) => user !== undefined)
        this.editWishlistUserSearch = ''
        this.editWishlistFilteredUserOptions = []
        this.editWishlistEditEmailInput = ''
      }

      this.editWishlistEmailInput = ''
    },
    handleCloseEditWishlistPopup() {
      this.editWishlistPopup = false
      this.editWishlist = {
        id: '',
        name: '',
        description: '',
        status: 'publish',
        is_default: false,
        is_public: false,
        url_code: '',
        emails: [],
        user_ids: [],
        allowed_roles: [],
        allowed_edit_emails: [],
        user_id: '',
      }
      this.editWishlistEmailInput = ''
      this.editWishlistSelectedUsers = []
      this.editWishlistSelectedRoles = []
      this.editWishlistEditEmailInput = ''
      this.editWishlistUserSearch = ''
      this.editWishlistFilteredUserOptions = []
      this.editWishlistRoleSearch = ''
      this.editWishlistFilteredRoleOptions = []
    },
    handleEditWishlist() {
      const isDefault = this.editWishlist.status === 'publish' ? this.editWishlist.is_default : false
      const data = {
        action: 'update_wishlist',
        id: this.editWishlist.id,
        name: this.editWishlist.name,
        description: this.editWishlist.description,
        status: this.editWishlist.status,
        is_default: isDefault === true ? '1' : '0',
        is_public: this.editWishlist.is_public === true ? '1' : '0',
        url_code: this.editWishlist.url_code,
        emails: this.editWishlist.emails,
        user_ids: this.editWishlist.user_ids,
        allowed_roles: this.editWishlist.allowed_roles,
        allowed_edit_emails: this.editWishlist.allowed_edit_emails,
      }

      this.editingWishlist = true

      saveCollection(data as any).then((res: any) => {
        notification.success({
          message: getI18n('success', __('Success', 'saveto-wishlist-lite-for-woocommerce')),
          description: res.message,
          class: 'wishlist-lists-success-notification',
        })

        this.editWishlistPopup = false
        this.editingWishlist = false
        this.wishlistData
      })
        .catch((e: any) => {
          notification.error({
            message: getI18n('error', __('Error', 'saveto-wishlist-lite-for-woocommerce')),
            description: getI18n('error_message', __('Failed to update wishlist.', 'saveto-wishlist-lite-for-woocommerce')),
            class: 'wishlist-lists-error-notification',
          })
        })
        .finally(() => {
          this.editWishlistPopup = false
          this.editingWishlist = false
        })
    },
    async handleCopy(text: string) {
      try {
        // Copy text to clipboard using JavaScript
        if (navigator.clipboard && window.isSecureContext) {
          await navigator.clipboard.writeText(text)
        } else {
          // fallback for older browsers
          const textarea = document.createElement('textarea')
          textarea.value = text
          textarea.style.position = 'fixed' // avoid scrolling to bottom
          textarea.style.opacity = '0'
          document.body.appendChild(textarea)
          textarea.focus()
          textarea.select()
          try {
            document.execCommand('copy')
          } finally {
            document.body.removeChild(textarea)
          }
        }
        this.copied = true
        setTimeout(() => {
          this.copied = false
        }, 2000)
      } catch (error) {
        console.error('Failed to copy text:', error)
      }
    },
  }
}

export default wishlistMounted