import { getSigner, ndk } from '@/ndk';
import { NDKEvent, type NDKKind, type NDKSubscription } from '@nostr-dev-kit/ndk';
import { LitElement, css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { map } from 'lit/directives/map.js';
import { when } from 'lit/directives/when.js';

import '@components/Arbor/ForumCategory';
import '@components/Arbor/ForumThread';
import '@components/Breadcrumbs';
import '@components/General/Prompt';

import type { EvePrompt } from '@components/General/Prompt';

interface ForumThread {
  id: string;
  title: string;
  author: string;
  description: string;
  created_at: string;
}

interface ForumCategory {
  id: string;
  name: string;
  threads: ForumThread[];
}

@customElement('arx-arbor-home')
export class ArborForum extends LitElement {
  @state()
  private categories: ForumCategory[] = [];

  private isSaving = false;

  private threadsQuery: NDKSubscription | undefined;

  @state()
  private forum: NDKEvent | null = null;

  static override styles = css`
    :host {
      display: block;
    }

    arx-button {
      margin-bottom: calc(var(--space-sm) / 2);
    }
  `;

  override async connectedCallback() {
    super.connectedCallback();
    await this.loadCategories();
  }

  newCategoryButtonClicked() {
    const prompt = this.shadowRoot?.getElementById('new-category-prompt') as EvePrompt;
    if (prompt) prompt.show();
  }

  private async doCreateCategory() {
    if (!this.forum) return;
    if (this.isSaving) return;
    this.isSaving = true;
    const prompt = this.shadowRoot?.getElementById('new-category-prompt') as EvePrompt;
    const newCategory = prompt.getValue();

    if (newCategory.length < 3) {
      alert('Category name must be at least 3 characters long');
      return;
    }

    try {
      await getSigner();
      const dtag = (Date.now() + Math.floor(Math.random() * 1000)).toString(32);
      const newForum = new NDKEvent(ndk);
      newForum.kind = 60890;
      newForum.tags = [...this.forum.tags, ['forum', `60891:${dtag}`, newCategory]];
      newForum.content = this.forum.content;
      await newForum.sign();
      await newForum.publish();
      this.forum = newForum;

      const categoryEvent = new NDKEvent(ndk);
      categoryEvent.kind = 60891;
      categoryEvent.tags = [
        ['d', dtag],
        ['name', newCategory],
      ];
      categoryEvent.content = '';
      await categoryEvent.sign();
      await categoryEvent.publish();

      this.categories = [
        ...this.categories,
        {
          id: dtag,
          name: newCategory,
          threads: [],
        },
      ];

      this.loadThreads();
    } catch (error) {
      console.error('Failed to create category:', error);
      alert('Failed to create category');
    } finally {
      this.isSaving = false;
    }
  }

  private async loadCategories() {
    await getSigner();
    this.forum = await ndk.fetchEvent({
      kinds: [60890 as NDKKind],
      '#d': ['arbor'],
    });
    if (!this.forum) {
      const event = new NDKEvent(ndk);
      event.kind = 60890;
      event.tags.push(['d', 'arbor']);
      event.content = '';
      await event.sign();
      await event.publish();
      this.forum = event;
    }
    for (const tag of this.forum.tags) {
      if (tag[0] === 'forum') {
        const [_, categoryId] = tag[1].split(':');
        this.categories = [
          ...this.categories,
          {
            id: categoryId,
            name: tag[2],
            threads: [],
          },
        ];
      }
    }
    this.loadThreads();
  }

  private async loadThreads() {
    if (this.threadsQuery) this.threadsQuery.stop();
    this.threadsQuery = ndk
      .subscribe({
        kinds: [892 as NDKKind],
        '#d': this.categories.map((category) => `60891:${category.id}`),
      })
      .on('event', (event) => {
        const categoryId = this.categories.findIndex(
          (category) => category.id === event.tags.find((tag) => tag[0] === 'd')?.[1].split(':')[1],
        );
        if (categoryId === -1) return;
        if (this.categories[categoryId].threads.find((thread) => thread.id === event.id)) return;
        this.categories[categoryId].threads = [
          ...this.categories[categoryId].threads,
          {
            id: event.id,
            title: event.tags.find((tag) => tag[0] === 'name')?.[1] || '',
            author: event.pubkey,
            description: event.content,
            created_at: new Date((event.created_at || 0) * 1000).toString(),
          },
        ];
        this.categories = [...this.categories];
      });
  }

  override render() {
    return html`
      <arx-breadcrumbs
        .items=${[{ text: 'Home', href: '/' }, { text: 'Arbor' }]}
      >
      </arx-breadcrumbs>

      <arx-button
        label="New Category"
        @click=${this.newCategoryButtonClicked}
      ></arx-button>

      <arx-prompt
        id="new-category-prompt"
        promptText="What would you like to call this category?"
        showInput
        placeholder="New Category"
        @save=${this.doCreateCategory}
      ></arx-prompt>

      ${map(
        this.categories,
        (category) => html`
          <arx-arbor-forum-category id=${category.id} title=${category.name}>
            ${when(category.threads.length === 0, () => html` <div style="padding: 1rem 1.5rem">No threads...</div> `)}
            ${map(
              category.threads,
              (thread) => html`
                <arx-arbor-forum-thread
                  id=${thread.id}
                  title=${thread.title}
                  description=${thread.description}
                  lastPostBy=${thread.author}
                  lastPostTime=${thread.created_at}
                >
                </arx-arbor-forum-thread>
              `,
            )}
          </arx-arbor-forum-category>
        `,
      )}
    `;
  }
}
