import { html, LitElement, nothing, type TemplateResult } from 'lit'
import maplibregl from 'maplibre-gl'
import app from '../store/app.ts'
import { from as nominatimToProperties } from '../store/adapters/nominatim.ts'
import { nominatimReverse } from '../utils/nominatim.ts'

type ResolvedProperties = ReturnType<typeof nominatimToProperties>

export class MBookmarkAddPopup extends LitElement {
  lat = 0
  lng = 0
  zoom = 12
  initialName = ''
  address?: string
  geocode = false

  #resolved: ResolvedProperties | undefined
  #geocoding = false
  #saved = false

  protected override createRenderRoot() {
    return this
  }

  override connectedCallback() {
    super.connectedCallback()
    if (this.geocode && !this.address && app.geocodingBookmarksEnabled) {
      this.#geocoding = true
      this.#reverseGeocode()
    }
  }

  async #reverseGeocode() {
    try {
      const result = await nominatimReverse(this.lat, this.lng)
      if (result?.display_name) {
        this.#resolved = nominatimToProperties(result)
        this.address = result.display_name
        const input = this.querySelector<HTMLInputElement>('input')
        const coordsPlaceholder = this.#coordsString()
        if (input && input.value === coordsPlaceholder) {
          input.value = result.display_name.split(',')[0].trim()
        }
      }
    } catch {
      // swallow; address just won't be populated
    } finally {
      this.#geocoding = false
      this.requestUpdate()
    }
  }

  #coordsString(): string {
    return `${this.lat.toFixed(5)}, ${this.lng.toFixed(5)}`
  }

  async #onSave() {
    const input = this.querySelector<HTMLInputElement>('input')
    const fallback = this.initialName || this.#coordsString()
    const name = input?.value.trim() || fallback
    this.#saved = true
    this.requestUpdate()
    await app.addBookmark(this.lat, this.lng, this.zoom, {
      ...(this.#resolved ?? {}),
      name,
      address: this.address ? { displayText: this.address } : undefined,
    })
  }

  override firstUpdated() {
    const input = this.querySelector<HTMLInputElement>('input')
    if (input) input.value = this.initialName || this.#coordsString()
  }

  override render(): TemplateResult {
    const addressText = this.address ??
      (this.#geocoding ? 'Looking up location…' : null)
    return html`
      <div class="bm-popup bm-popup--add">
        ${addressText
          ? html`
            <p class="bm-popup-address">${addressText}</p>
          `
          : nothing}
        <input type="text" placeholder="Bookmark name" />
        <button
          class="bm-popup-save"
          ?disabled="${this.#saved}"
          @click="${this.#onSave}"
        >
          ${this.#saved ? 'Saved!' : 'Add to bookmarks'}
        </button>
      </div>
    `
  }
}

customElements.define('m-bookmark-add-popup', MBookmarkAddPopup)

export type BookmarkAddPopupOptions = {
  lat: number
  lng: number
  zoom: number
  initialName?: string
  address?: string
  geocode?: boolean
}

export function createBookmarkAddPopup(
  opts: BookmarkAddPopupOptions,
): maplibregl.Popup {
  const el = document.createElement(
    'm-bookmark-add-popup',
  ) as MBookmarkAddPopup
  el.lat = opts.lat
  el.lng = opts.lng
  el.zoom = opts.zoom
  el.initialName = opts.initialName ?? ''
  el.address = opts.address
  el.geocode = opts.geocode ?? false
  return new maplibregl.Popup({ offset: 25 }).setDOMContent(el)
}
