import { html, LitElement, nothing, type TemplateResult } from 'lit'
import app from '../store/app.ts'
import {
  type Bookmark,
  type BookmarkList,
  type SharedBookmark,
  toSharedBookmark,
} from '../store/schema.ts'
import { icon } from '../utils/icon.ts'
import { setListFilter } from '../utils/list-view.ts'
import { setEditMode } from '../utils/list-edit-mode.ts'
import { ListDetailController } from '../utils/list-detail-view.ts'
import { pointInBounds } from '../utils/bounds.ts'
import {
  downloadBookmarks,
  type ExportFormat,
  type ExportScopeOption,
  renderExportDialog,
} from '../utils/bookmark-export.ts'
import '../components/m-mini-map.ts'
import '../components/m-bookmarks-list.ts'

/**
 * The `/list/{id}` detail page: a mini-map and the list's bookmarks, in a
 * similar layout to the public share page (`share-view.ts`), but the rows
 * themselves are the owner-side `m-bookmarks-list` (live `Bookmark`s, with
 * edit-mode bulk actions and links into `/bookmark/{id}`) rather than
 * `ListDetailController`'s read-only `SharedBookmark` row renderer — that one
 * stays reserved for `share-view.ts`, the public unauthenticated viewer.
 * Renaming/recoloring and deleting the list live in the header
 * (`m-list-header`), not here; this page is the browsing surface plus "View
 * on map" and "Export".
 */
export class ListPage extends LitElement {
  static override properties = {
    listId: { attribute: 'list-id' },
  }

  declare listId: string
  #detail = new ListDetailController(this)
  #exportOpen = false
  #exportScope: 'all' | 'visible' = 'all'

  protected override createRenderRoot() {
    return this
  }

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

  override connectedCallback() {
    super.connectedCallback()
    setEditMode(false)
    app.addEventListener(this.#onUpdate)
  }

  override disconnectedCallback() {
    super.disconnectedCallback()
    app.removeEventListener(this.#onUpdate)
  }

  #list(): BookmarkList | undefined {
    return app.bookmarkLists.find((l) => l.id === this.listId)
  }

  #bookmarks(): Bookmark[] {
    return app.bookmarksInList(this.listId)
  }

  /** Only the bookmarks currently within the mini-map's viewport. */
  #visibleBookmarks(all: Bookmark[]): Bookmark[] {
    const bounds = this.#detail.bounds
    if (!bounds) return all
    return all.filter((b) => pointInBounds(b.geometry.coordinates, bounds))
  }

  #points(): SharedBookmark[] {
    return this.#bookmarks().map((b) => toSharedBookmark(b))
  }

  #viewOnMap = (): void => {
    setListFilter(this.listId)
    globalThis.location.hash = '#!/'
  }

  #openExport = (): void => {
    this.#exportOpen = true
    this.requestUpdate()
  }

  #dismissExport = (): void => {
    this.#exportOpen = false
    this.requestUpdate()
  }

  #setExportScope = (scope: 'all' | 'visible'): void => {
    this.#exportScope = scope
    this.requestUpdate()
  }

  #doExport = (format: ExportFormat): void => {
    const list = this.#list()
    if (!list) return
    const all = this.#points()
    const visible = this.#detail.visibleBookmarks(all)
    const filtered = visible.length < all.length
    const points = filtered && this.#exportScope === 'visible' ? visible : all
    downloadBookmarks(points, list.name, format)
    this.#dismissExport()
  }

  override render(): TemplateResult {
    const list = this.#list()
    if (!list) {
      return html`
        <section class="share-view">
          <p class="share-view-error">This list doesn't exist.</p>
          <a class="share-view-open" href="#!/bookmarks">Back to bookmarks →</a>
        </section>
      `
    }

    const all = this.#points()
    const count = all.length
    const visiblePoints = this.#detail.visibleBookmarks(all)
    const filtered = visiblePoints.length < count
    const exportScopeOption: ExportScopeOption | undefined = filtered
      ? {
        allCount: count,
        visibleCount: visiblePoints.length,
        scope: this.#exportScope,
        onScopeChange: this.#setExportScope,
      }
      : undefined
    const visibleBookmarks = this.#visibleBookmarks(this.#bookmarks())

    return html`
      <section class="share-view">
        ${count
          ? html`
            <m-mini-map
              .points="${all}"
              .color="${list.color ?? null}"
              @mini-map-viewport="${this.#detail.onViewport}"
            ></m-mini-map>
          `
          : nothing}
        <div class="share-view-body">
          <div class="share-view-header">
            <h1 class="share-view-title">
              ${list.color
                ? html`
                  <span
                    class="share-view-swatch"
                    style="background:${list.color}"
                    aria-hidden="true"
                  ></span>
                `
                : nothing} ${list.name}
            </h1>
            ${count
              ? html`
                <div class="share-view-actions">
                  <button
                    type="button"
                    class="share-view-action-btn"
                    @click="${this.#viewOnMap}"
                  >
                    ${icon('navigation', '16px')}
                    <span class="share-view-action-label">View on map</span>
                  </button>
                  <button
                    type="button"
                    class="share-view-action-btn"
                    @click="${this.#openExport}"
                  >
                    ${icon('download', '16px')}
                    <span class="share-view-action-label">Export</span>
                  </button>
                </div>
              `
              : nothing}
          </div>
          ${count
            ? html`
              <p class="share-view-coords">
                ${filtered
                  ? html`${visiblePoints.length} of ${count} locations`
                  : html`${count} ${count === 1 ? 'location' : 'locations'}`}
                ${filtered
                  ? html`
                    <button
                      type="button"
                      class="link share-view-reset"
                      @click="${() => this.#detail.resetView()}"
                    >
                      Show all
                    </button>
                  `
                  : nothing}
              </p>
              ${visibleBookmarks.length
                ? html`
                  <m-bookmarks-list
                    .bookmarks="${visibleBookmarks}"
                    .lists="${app.bookmarkLists}"
                  ></m-bookmarks-list>
                `
                : filtered
                ? html`
                  <p class="share-view-list-empty">No locations in view.</p>
                `
                : nothing}
            `
            : html`
              <p class="bm-empty bm-empty--folder">No bookmarks in this list.</p>
            `}
        </div>
      </section>
      ${renderExportDialog(
        this.#exportOpen,
        this.#doExport,
        this.#dismissExport,
        exportScopeOption,
      )}
    `
  }
}

customElements.define('r-list', ListPage)
