import { html, TemplateResult } from 'lit'
import { type CellRenderOptions, DataTable } from '../DataTable.js'
import { property } from 'lit/decorators.js'
import { until } from 'lit/directives/until.js'
import { LiveData } from '../../../reactive/LiveData.js'
import type { TrashEntry } from '@api-client/core/models/TrashEntry.js'
import type { IUser } from '@api-client/core/models/store/User.js'
import { relativeDay } from '../../../lib/time/Conversion.js'
import type { UiMenuElement } from '../../../md/menu/ui-menu.js'
import { fileIcon } from '../../../lib/files/Utils.js'
import services from '../../../services/api_service.js'
import type { UiMenuItemElement } from '../../../md/menu/ui-menu-item.js'

import '../../../md/icon-button/ui-icon-button.js'
import '../../../md/icons/ui-icon.js'
import '../../../md/menu/ui-menu.js'
import '../../../md/menu/ui-menu-item.js'

/**
 * A class that render QuickAPI file's trash.
 *
 * @fires rowaction - Dispatched when the user triggers an action on the item.
 *     - `detail`: An object with a `key` and `action` property
 *     - Example: `{ key: 'abc', action: 'delete' }`
 * @attribute sort
 * @attribute sortDirection
 */
export default class TrashDataTable extends DataTable<TrashEntry> {
  @property({ type: Object }) accessor user: IUser | undefined
  @property({ type: String }) accessor oid: string | undefined

  // @ts-expect-error This is to explicitly declare a type as LitPlugin does not handle this situation.
  declare items: LiveData<TrashEntry[]> | undefined

  handleFileMenuSelect(e: CustomEvent<{ item: UiMenuItemElement }>): void {
    const menu = e.currentTarget as UiMenuElement
    const { key } = menu.dataset
    if (!key) {
      return
    }
    const action = e.detail.item.value
    if (!action) {
      return
    }
    this.dispatchEvent(new CustomEvent('rowaction', { detail: { key, action } }))
  }

  override renderEmpty(): TemplateResult {
    return html`<slot name="empty"><p class="empty">You have no trash.</p></slot>`
  }

  override renderHeader(): TemplateResult[] {
    return [
      this.renderHeaderCell('Name', 0, { sort: 'name' }),
      this.renderHeaderCell('Owner', 1),
      this.renderHeaderCell('Trashed date', 2),
      this.renderHeaderCell(html`<span hidden aria-label="Row options">Menu</span>`, 3, { delegateFocus: true }),
    ]
  }

  override renderRowValues(item: TrashEntry, index: number): TemplateResult[] {
    return [
      this.#nameCell(item, index, 0),
      this.#ownerCell(item, index, 1),
      this.#updatedCell(item, index, 2),
      this.renderCell(this.#renderEntryMenu(item), index, 3, { classes: ['actions'], delegateFocus: true }),
    ]
  }

  #nameCell(item: TrashEntry, row: number, col: number): TemplateResult {
    const icon = fileIcon(item)
    const content = html`<ui-icon class="cell-icon" role="presentation">${icon}</ui-icon> ${item.info.name}`
    return this.renderCell(content, row, col, { classes: ['primary-cell'], isPrimary: true })
  }

  #ownerCell(item: TrashEntry, row: number, col: number): TemplateResult {
    const opts: CellRenderOptions = {
      classes: ['owner'],
    }
    const { user } = this
    if (!user) {
      return this.renderCell(html`--`, row, col, opts)
    }
    if (item.info.byMe) {
      return this.renderCell(
        html`<ui-user-avatar role="presentation" class="avatar body-small" .user="${user}" type="icon"></ui-user-avatar
          ><span aria-label="Owned by me" class="user-label">me</span>`,
        row,
        col,
        opts
      )
    }
    const content = this.#ownerCellAsync(item.info.user)
    const loader = html`<span class="owner-loading">loading...</span>`
    return this.renderCell(html`${until(content, loader)}`, row, col, opts)
  }

  async #ownerCellAsync(key?: string): Promise<TemplateResult> {
    if (!key) {
      return html` <span aria-label="Owned by unknown user">unknown</span> `
    }
    // @TODO: Use a context provider and decouple from services singleton
    const cache = await services.get('userCache')
    const user = await cache.getUser(key)
    if (!user) {
      return html` <span aria-label="Owned by unknown user">unknown</span> `
    }
    return html`<ui-user-avatar
        role="presentation"
        class="avatar body-small"
        .user="${user}"
        type="icon"
      ></ui-user-avatar
      ><span aria-label="Owned by ${user.name}" class="user-label">${user.name}</span>`
  }

  #updatedCell(item: TrashEntry, row: number, col: number): TemplateResult {
    const opts: CellRenderOptions = {
      classes: ['updated'],
    }
    const { time } = item.info
    const relative = relativeDay(time)
    return this.renderCell(html`<span>${relative}</span>`, row, col, opts)
  }

  #renderEntryMenu(item: TrashEntry): TemplateResult {
    const { key } = item
    return html`
      <ui-icon-button
        data-key="${key}"
        id="anchor-${key}"
        aria-controls="menu-${key}"
        tabindex="-1"
        popoverTarget="menu-${key}"
        aria-label="More options for ${item.info.name}"
      >
        <ui-icon>more_vert</ui-icon>
      </ui-icon-button>
      <ui-menu
        class="item-menu"
        popover="auto"
        id="menu-${key}"
        data-key="${key}"
        @select="${this.handleFileMenuSelect}"
      >
        <ui-menu-item value="restore">
          <div>Restore</div>
          <ui-icon slot="start">restore_page</ui-icon>
        </ui-menu-item>
        <ui-menu-item value="delete">
          <div>Delete forever</div>
          <ui-icon slot="start">delete_forever</ui-icon>
        </ui-menu-item>
      </ui-menu>
    `
  }
}
