import { html, LitElement, nothing, type TemplateResult } from 'lit'
import { Router, type SharePublisher, type ShareView } from '@civility/ui'
import app from '../store/app.ts'
import { icon } from '../utils/icon.ts'
import {
  isEditMode,
  LIST_EDIT_MODE_EVENT,
  toggleEditMode,
} from '../utils/list-edit-mode.ts'

/**
 * Title bar for the `/list/{id}` detail page: the list's name, how many
 * locations it holds, a back link, the share control, and a menu for
 * renaming/recoloring or deleting the list.
 *
 * Mounted as the router's `header` landmark, separate from `r-list` in
 * `main`, so list-level actions live here rather than duplicated per-page.
 * Subscribes to the app store so a rename or an added bookmark lands here
 * without re-navigating; the route only carries the id.
 *
 * Renders header markup directly rather than wrapping `ui-header-content`,
 * which renders into its own light DOM and would discard slotted actions.
 */
export class MListHeader extends LitElement {
  static override properties = {
    listId: { attribute: 'list-id' },
  }

  declare listId: string
  #shareOpen = false
  #shareView: ShareView | null = null
  /** Asks which viewport a brand-new share link should open to — see `#openShare`. */
  #viewChoiceOpen = false
  #menuOpen = false
  #editing = false

  protected override createRenderRoot() {
    return this
  }

  #onAppUpdate = () => this.requestUpdate()

  // Any click that isn't inside the open menu dismisses it — same pattern
  // as the per-list menu on `/bookmarks`.
  #onDocumentClick = (e: Event) => {
    if (!this.#menuOpen) return
    const path = e.composedPath()
    const menu = this.querySelector('.header-menu')
    if (menu && path.includes(menu)) return
    this.#menuOpen = false
    this.requestUpdate()
  }

  override connectedCallback() {
    super.connectedCallback()
    app.addEventListener(this.#onAppUpdate)
    document.addEventListener('click', this.#onDocumentClick)
    globalThis.addEventListener(LIST_EDIT_MODE_EVENT, this.#onAppUpdate)
  }

  override disconnectedCallback() {
    super.disconnectedCallback()
    app.removeEventListener(this.#onAppUpdate)
    document.removeEventListener('click', this.#onDocumentClick)
    globalThis.removeEventListener(LIST_EDIT_MODE_EVENT, this.#onAppUpdate)
  }

  #toggleMenu = (): void => {
    this.#menuOpen = !this.#menuOpen
    this.requestUpdate()
  }

  #toggleSelectMode = (): void => {
    toggleEditMode()
    this.#menuOpen = false
    this.requestUpdate()
  }

  #editList = (): void => {
    this.#menuOpen = false
    this.#editing = true
    this.requestUpdate()
  }

  #dismissEdit = (): void => {
    this.#editing = false
    this.requestUpdate()
  }

  #submitEditList = async (e: Event): Promise<void> => {
    e.preventDefault()
    const form = e.target as HTMLFormElement
    const fd = new FormData(form)
    const name = (fd.get('name') as string).trim()
    const color = (fd.get('color') as string) || undefined
    if (!name) return
    await app.updateList(this.listId, { name, color })
    this.#editing = false
    this.requestUpdate()
  }

  #deleteList = async (): Promise<void> => {
    this.#menuOpen = false
    this.requestUpdate()
    const name = this.#list()?.name ?? 'this list'
    if (
      !globalThis.confirm(
        `Delete "${name}"? Its bookmarks are kept, but any shared link to the list stops working.`,
      )
    ) return
    await app.deleteList(this.listId)
    Router.goBack('#!/bookmarks')
  }

  #sharePublisher: SharePublisher = {
    publish: async () => {
      const { id, url } = await app.publishList(this.listId)
      this.#shareView = { id, url, label: this.#list()?.name }
      return this.#shareView
    },
    revoke: async (id: string) => {
      await app.revokeShare(id)
      this.#shareView = null
    },
  }

  #list() {
    return app.bookmarkLists.find((c) => c.id === this.listId)
  }

  #openShare = async () => {
    // Preload any existing share so the dialog opens straight into manage
    // mode (link + revoke) rather than offering to mint a second one. A
    // fresh share instead asks which viewport to bake into the link.
    const record = await app.shareForList(this.listId)
    if (record) {
      const url = await app.shareUrlFor(record.id)
      this.#shareView = url
        ? { id: record.id, url, label: this.#list()?.name }
        : null
      this.#shareOpen = true
      this.requestUpdate()
      return
    }
    this.#viewChoiceOpen = true
    this.requestUpdate()
  }

  #createShare = async (useCurrentView: boolean) => {
    this.#viewChoiceOpen = false
    this.requestUpdate()
    try {
      const { id, url } = await app.publishList(this.listId, {
        useCurrentView,
      })
      this.#shareView = { id, url, label: this.#list()?.name }
      this.#shareOpen = true
    } catch (e) {
      globalThis.alert(
        e instanceof Error ? e.message : 'Could not create link.',
      )
    }
    this.requestUpdate()
  }

  #dismissViewChoice = () => {
    this.#viewChoiceOpen = false
    this.requestUpdate()
  }

  /** Helper text under the "current view" option — what it'll actually bake in. */
  #currentViewSummary(): string {
    const view = app.lastView
    if (!view) return ''
    return `Opens at zoom ${Math.round(view.zoom)}`
  }

  override render(): TemplateResult {
    const list = this.#list()
    const count = app.bookmarksInList(this.listId).length

    return html`
      <button
        class="header-back"
        aria-label="Go back"
        @click="${() => Router.goBack('#!/bookmarks')}"
      >
        ${icon('arrow-left', '20px')}
      </button>
      <h1>${list?.name ?? 'List'}</h1>
      <div class="header-actions">
        <span class="list-view-count">
          ${count} ${count === 1 ? 'location' : 'locations'}
        </span>
        <button
          class="bm-icon-btn"
          aria-label="Share this list"
          @click="${this.#openShare}"
        >
          ${icon('share-2', '18px')}
        </button>
        <div class="header-menu">
          <button
            class="bm-icon-btn"
            aria-label="List actions"
            aria-expanded="${this.#menuOpen}"
            @click="${this.#toggleMenu}"
          >
            ${icon('more-vertical', '18px')}
          </button>
          ${this.#menuOpen
            ? html`
              <div class="header-menu-panel" role="menu">
                <button
                  class="header-menu-item"
                  role="menuitem"
                  @click="${this.#editList}"
                >
                  ${icon('edit', '18px')}
                  <span>Edit list</span>
                </button>
                <button
                  class="header-menu-item"
                  role="menuitem"
                  @click="${this.#toggleSelectMode}"
                >
                  ${icon('check-square', '18px')}
                  <span>${isEditMode()
                    ? 'Cancel selection'
                    : 'Select Bookmarks'}</span>
                </button>
                <button
                  class="header-menu-item"
                  role="menuitem"
                  @click="${this.#deleteList}"
                >
                  ${icon('x', '18px')}
                  <span>Delete list</span>
                </button>
              </div>
            `
            : nothing}
        </div>
      </div>

      <ui-dialog ?open="${this.#editing}" @dismiss="${this.#dismissEdit}">
        <dialog>
          <article class="bm-dialog">
            ${list
              ? html`
                <h2 class="bm-dialog-title">Edit List</h2>
                <form @submit="${this.#submitEditList}">
                  <input
                    name="name"
                    type="text"
                    placeholder="List name"
                    .value="${list.name}"
                    required
                    autocomplete="off"
                    autofocus
                  >
                  <div class="bm-folder-color-row">
                    <label for="edit-list-color">Color</label>
                    <input
                      id="edit-list-color"
                      name="color"
                      type="color"
                      .value="${list.color ?? '#e05c2a'}"
                    >
                  </div>
                  <div class="bm-form-actions">
                    <button type="submit">Save</button>
                    <button type="button" class="link" @click="${this
                      .#dismissEdit}">
                      Cancel
                    </button>
                  </div>
                </form>
              `
              : nothing}
          </article>
        </dialog>
      </ui-dialog>

      <civ-share-dialog
        .open="${this.#shareOpen}"
        .methods="${this.#sharePublisher}"
        .share="${this.#shareView}"
        heading="Share list"
        @on-published="${() => this.requestUpdate()}"
        @on-revoked="${() => {
          this.#shareView = null
          this.requestUpdate()
        }}"
        @dismiss="${() => {
          this.#shareOpen = false
          this.requestUpdate()
        }}"
      ></civ-share-dialog>

      <ui-dialog ?open="${this.#viewChoiceOpen}" @dismiss="${this
        .#dismissViewChoice}">
        <dialog>
          <article class="bm-dialog">
            <h2 class="bm-dialog-title">Share list</h2>
            <p>Choose what the link opens to.</p>
            <div class="bm-scope-toggle">
              <button
                type="button"
                class="bm-scope-btn"
                @click="${() => this.#createShare(false)}"
              >
                ${icon('globe', '20px')}<br>Show All
              </button>
              <button
                type="button"
                class="bm-scope-btn"
                @click="${() => this.#createShare(true)}"
              >
                ${icon('map-pin', '20px')}<br>Currently Visible
              </button>
            </div>
            <p class="bm-dialog-coords">${this.#currentViewSummary()}</p>
            <div class="bm-form-actions">
              <button type="button" class="link" @click="${this
                .#dismissViewChoice}">
                Cancel
              </button>
            </div>
          </article>
        </dialog>
      </ui-dialog>
    `
  }
}

customElements.define('m-list-header', MListHeader)
