import { LitElement, html, css } from 'lit';
import {
    customElement,
    property,
    state,
} from 'lit/decorators.js';
import * as library from '@go/library/models.js';
import { LibraryController } from '@store/controllers/library-controller';
import {
    GetArtistImageURL,
    GetArtistImageCachedPath,
    GetArtistMBID,
} from '@go/explore/service.js';
import '@awesome.me/webawesome/dist/components/icon/icon.js';
import '@components/cover-grid/cover-grid.js';
import { designTokens } from '../../styles/tokens.css';

@customElement('artist-details')
export class ArtistDetails extends LitElement {
    @property({ type: Number, attribute: 'artist-id' })
    artistId = 0;

    @property({ type: String, attribute: 'artist-name' })
    artistName = '';

    @property({ type: String, attribute: 'artist-mbid' })
    artistMBID = '';

    @state()
    private albums: library.Album[] = [];

    @state()
    private loading = true;

    @state()
    private artistImageURL = '';

    private libraryCtrl = new LibraryController(this);

    /** Tracks the store's cached array reference to detect refreshes. */
    private lastAlbumsRef: library.Album[] | null = null;

    static override styles = [designTokens, css`
        :host {
            display: flex;
            flex-direction: column;
            overflow: hidden;
            height: 100%;
            box-sizing: border-box;
        }

        /* ====================================
         * Header
         * ==================================== */

        .artist-header {
            display: flex;
            align-items: center;
            gap: 20px;
            padding: 16px 20px;
            flex-shrink: 0;
            border-bottom: 1px solid
                var(
                    --yj-border-subtle,
                    rgba(255, 255, 255, 0.06)
                );
        }

        .back-button {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 32px;
            height: 32px;
            border: none;
            border-radius: 50%;
            background: var(
                --yj-bg-overlay,
                rgba(255, 255, 255, 0.06)
            );
            color: var(--yj-text-primary, #fff);
            cursor: pointer;
            flex-shrink: 0;
            transition: background-color 0.15s ease;
        }

        .back-button:hover {
            background: var(
                --yj-bg-hover,
                rgba(255, 255, 255, 0.12)
            );
        }

        .back-button wa-icon {
            font-size: 16px; /* back button — outside type scale */
        }

        .artist-avatar {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            overflow: hidden;
            background: linear-gradient(
                135deg,
                var(--yj-bg-overlay, #404040) 0%,
                var(--yj-bg-surface, #282828) 100%
            );
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }

        .artist-avatar img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .artist-avatar .initial {
            color: var(
                --yj-text-secondary,
                #b3b3b3
            );
            font-size: 32px; /* large decorative initial */
            font-weight: 600;
            text-transform: uppercase;
            user-select: none;
            line-height: 1;
        }

        .artist-info {
            display: flex;
            flex-direction: column;
            gap: 4px;
            min-width: 0;
        }

        .artist-title {
            font-size: 24px; /* page title — outside type scale */
            font-weight: 700;
            color: var(--yj-text-primary, #fff);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            margin: 0;
            line-height: 1.2;
        }

        .album-count {
            font-size: var(--yj-text-md);
            color: var(
                --yj-text-secondary,
                #b3b3b3
            );
        }

        /* ====================================
         * Content
         * ==================================== */

        .content {
            flex: 1;
            overflow: hidden;
        }

        cover-grid {
            width: 100%;
            height: 100%;
        }

    `];

    override connectedCallback() {
        super.connectedCallback();
        this.loadAlbums();
        this.loadArtistImage();
    }

    override updated() {
        const cached = this.libraryCtrl.cachedAlbums;

        if (
            cached !== null &&
            cached !== this.lastAlbumsRef
        ) {
            this.lastAlbumsRef = cached;
            this.loadAlbums();
        }
    }

    /* ================================================================
     * Data loading
     * ================================================================ */

    private async loadArtistImage() {
        // Resolve MBID from tags if not provided via attribute.
        let mbid = this.artistMBID;

        if (!mbid && this.artistName) {
            try {
                mbid = await GetArtistMBID(this.artistName);
            } catch {
                return;
            }
        }

        if (!mbid) return;

        try {
            // Disk cache first — the resolving call below is MB →
            // Wikidata → Wikipedia → Wikimedia, and most artists this
            // page renders have been resolved once already.
            const cached = await GetArtistImageCachedPath(mbid);

            if (cached) {
                this.artistImageURL = cached;

                return;
            }

            const url = await GetArtistImageURL(mbid);

            if (url) {
                this.artistImageURL = url;
            }
        } catch {
            // No image — avatar stays as initial letter.
        }
    }

    private async loadAlbums() {
        if (!this.artistId) return;

        // Try to populate instantly from the
        // cached all-albums list if available.
        const cached =
            this.libraryCtrl.getAlbumsByArtistNameCached(
                this.artistName,
            );

        if (cached !== null && cached.length > 0) {
            this.albums = cached;
            this.loading = false;
        }

        // Always run the authoritative backend
        // query.  If we got a cache hit above,
        // this serves as a correction pass.
        try {
            const albums =
                await this.libraryCtrl.getAlbumsByArtist(
                    this.artistName,
                );

            const result = albums ?? [];

            // Skip update if the cached result
            // is identical (same IDs in same
            // order) to avoid a re-render.
            if (!this.albumsMatch(result)) {
                this.albums = result;
            }
        } catch (error) {
            console.error(
                'Error loading artist albums:',
                error,
            );

            // Only overwrite if we had no cached
            // result to fall back on.
            if (cached === null) {
                this.albums = [];
            }
        } finally {
            this.loading = false;
        }
    }

    /**
     * Compare two album lists by ID to avoid
     * unnecessary re-renders when the backend
     * result matches the cached approximation.
     */
    private albumsMatch(
        incoming: library.Album[],
    ): boolean {
        const current = this.albums;

        if (current.length !== incoming.length) {
            return false;
        }

        for (let i = 0; i < current.length; i++) {
            if (
                current[i]!.ID !== incoming[i]!.ID
            ) {
                return false;
            }
        }

        return true;
    }

    /* ================================================================
     * Navigation
     * ================================================================ */

    private navigateBack() {
        this.dispatchEvent(
            new CustomEvent('navigate', {
                bubbles: true,
                composed: true,
                detail: { view: 'artists' },
            }),
        );
    }

    /* ================================================================
     * Helpers
     * ================================================================ */

    private getInitial(name: string): string {
        if (!name) return '?';

        return name.charAt(0).toUpperCase();
    }

    /* ================================================================
     * Rendering
     * ================================================================ */

    override render() {
        const albumCount = this.albums.length;
        const albumLabel =
            albumCount === 1 ? 'album' : 'albums';

        return html`
            <div class="artist-header">
                <button
                    class="back-button"
                    @click=${this.navigateBack}
                    title="Back to artists"
                    aria-label="Back to artists"
                >
                    <wa-icon
                        name="arrow-left"
                    ></wa-icon>
                </button>
                <div class="artist-avatar">
                    ${this.artistImageURL
                        ? html`<img
                              src="${this.artistImageURL}"
                              alt="${this.artistName}"
                          />`
                        : html`<span class="initial">
                              ${this.getInitial(this.artistName)}
                          </span>`}
                </div>
                <div class="artist-info">
                    <h1
                        class="artist-title"
                        title="${this.artistName}"
                    >
                        ${this.artistName}
                    </h1>
                    ${!this.loading
                        ? html`
                              <span
                                  class="album-count"
                              >
                                  ${albumCount}
                                  ${albumLabel}
                              </span>
                          `
                        : ''}
                </div>
            </div>
            <div class="content">
                <cover-grid
                    .externalAlbums=${this.albums}
                ></cover-grid>
            </div>
        `;
    }
}
