import * as plugins from '../plugins.js';
import { apiService } from '../services/index.js';
import { themeStyles } from '../styles/index.js';

const { html, css, cssManager, customElement, property, state, DeesElement } = plugins;
const { DeesContextmenu } = plugins.deesCatalog;

@customElement('tsview-mongo-documents')
export class TsviewMongoDocuments extends DeesElement {
  @property({ type: String })
  public accessor databaseName: string = '';

  @property({ type: String })
  public accessor collectionName: string = '';

  @state()
  private accessor documents: Record<string, unknown>[] = [];

  @state()
  private accessor total: number = 0;

  @state()
  private accessor page: number = 1;

  @state()
  private accessor pageSize: number = 50;

  @state()
  private accessor loading: boolean = false;

  @state()
  private accessor filterText: string = '';

  @state()
  private accessor selectedId: string = '';

  public static styles = [
    cssManager.defaultStyles,
    themeStyles,
    css`
      :host {
        display: block;
        height: 100%;
        overflow: hidden;
      }

      .documents-container {
        display: flex;
        flex-direction: column;
        height: 100%;
      }

      .filter-bar {
        display: flex;
        gap: 12px;
        padding: 12px;
        border-bottom: 1px solid #333;
      }

      .filter-input {
        flex: 1;
        padding: 8px 12px;
        background: rgba(0, 0, 0, 0.3);
        border: 1px solid #444;
        border-radius: 6px;
        color: #fff;
        font-size: 13px;
        font-family: monospace;
      }

      .filter-input:focus {
        outline: none;
        border-color: #404040;
      }

      .filter-input::placeholder {
        color: #666;
      }

      .filter-btn {
        padding: 8px 16px;
        background: rgba(255, 255, 255, 0.1);
        border: 1px solid #404040;
        color: #e0e0e0;
        border-radius: 6px;
        cursor: pointer;
        font-size: 13px;
      }

      .filter-btn:hover {
        background: rgba(255, 255, 255, 0.15);
      }

      .documents-list {
        flex: 1;
        overflow-y: auto;
        padding: 8px;
      }

      .document-row {
        padding: 10px 12px;
        border-radius: 6px;
        cursor: pointer;
        margin-bottom: 4px;
        background: rgba(0, 0, 0, 0.2);
        transition: background 0.1s;
      }

      .document-row:hover {
        background: rgba(255, 255, 255, 0.05);
      }

      .document-row.selected {
        background: rgba(255, 255, 255, 0.08);
        border: 1px solid rgba(255, 255, 255, 0.15);
      }

      .document-id {
        font-size: 12px;
        color: #e0e0e0;
        font-family: monospace;
        margin-bottom: 4px;
      }

      .document-preview {
        font-size: 12px;
        color: #888;
        font-family: monospace;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 100%;
      }

      .pagination {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 12px;
        border-top: 1px solid #333;
        font-size: 13px;
        color: #888;
      }

      .pagination-info {
        display: flex;
        align-items: center;
        gap: 8px;
      }

      .pagination-controls {
        display: flex;
        gap: 4px;
      }

      .page-btn {
        padding: 6px 12px;
        background: transparent;
        border: 1px solid #444;
        color: #888;
        border-radius: 4px;
        cursor: pointer;
        font-size: 12px;
      }

      .page-btn:hover:not(:disabled) {
        border-color: #666;
        color: #aaa;
      }

      .page-btn:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }

      .empty-state {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 200px;
        color: #666;
      }

      .loading-state {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 200px;
        color: #888;
      }

      .actions-bar {
        display: flex;
        justify-content: flex-end;
        padding: 8px 12px;
        border-bottom: 1px solid #333;
      }

      .action-btn {
        padding: 6px 12px;
        background: rgba(34, 197, 94, 0.2);
        border: 1px solid #22c55e;
        color: #4ade80;
        border-radius: 4px;
        cursor: pointer;
        font-size: 12px;
      }

      .action-btn:hover {
        background: rgba(34, 197, 94, 0.3);
      }
    `,
  ];

  async connectedCallback() {
    super.connectedCallback();
    await this.loadDocuments();
  }

  updated(changedProperties: Map<string, unknown>) {
    if (changedProperties.has('databaseName') || changedProperties.has('collectionName')) {
      this.page = 1;
      this.loadDocuments();
    }
  }

  private async loadDocuments() {
    if (!this.databaseName || !this.collectionName) return;

    this.loading = true;
    try {
      let filter = {};
      if (this.filterText.trim()) {
        try {
          filter = JSON.parse(this.filterText);
        } catch {
          // Invalid JSON, ignore filter
        }
      }

      const result = await apiService.findDocuments(
        this.databaseName,
        this.collectionName,
        {
          filter,
          skip: (this.page - 1) * this.pageSize,
          limit: this.pageSize,
        }
      );

      this.documents = result.documents;
      this.total = result.total;
    } catch (err) {
      console.error('Error loading documents:', err);
      this.documents = [];
      this.total = 0;
    }
    this.loading = false;
  }

  /**
   * Public method to refresh documents (called by parent on change events)
   */
  public async refresh() {
    await this.loadDocuments();
  }

  private handleFilterInput(e: Event) {
    this.filterText = (e.target as HTMLInputElement).value;
  }

  private handleFilterSubmit() {
    this.page = 1;
    this.loadDocuments();
  }

  private handleKeyPress(e: KeyboardEvent) {
    if (e.key === 'Enter') {
      this.handleFilterSubmit();
    }
  }

  private selectDocument(doc: Record<string, unknown>) {
    const id = (doc._id as string) || '';
    this.selectedId = id;

    this.dispatchEvent(
      new CustomEvent('document-selected', {
        detail: { documentId: id, document: doc },
        bubbles: true,
        composed: true,
      })
    );
  }

  private goToPage(pageNum: number) {
    this.page = pageNum;
    this.loadDocuments();
  }

  private getDocumentPreview(doc: Record<string, unknown>): string {
    const preview: Record<string, unknown> = {};
    const keys = Object.keys(doc).filter((k) => k !== '_id');
    for (const key of keys.slice(0, 3)) {
      preview[key] = doc[key];
    }
    return JSON.stringify(preview);
  }

  private get totalPages(): number {
    return Math.ceil(this.total / this.pageSize);
  }

  private async handleInsertNew() {
    const newDoc = {
      // Default empty document
      createdAt: new Date().toISOString(),
    };

    try {
      const insertedId = await apiService.insertDocument(
        this.databaseName,
        this.collectionName,
        newDoc
      );
      await this.loadDocuments();
      this.selectedId = insertedId;
      this.dispatchEvent(
        new CustomEvent('document-selected', {
          detail: { documentId: insertedId },
          bubbles: true,
          composed: true,
        })
      );
    } catch (err) {
      console.error('Error inserting document:', err);
    }
  }

  private handleDocumentContextMenu(event: MouseEvent, doc: Record<string, unknown>) {
    event.preventDefault();
    const docId = doc._id as string;

    DeesContextmenu.openContextMenuWithOptions(event, [
      {
        name: 'View/Edit',
        iconName: 'lucide:edit',
        action: async () => {
          this.selectDocument(doc);
        },
      },
      {
        name: 'Copy as JSON',
        iconName: 'lucide:copy',
        action: async () => {
          await navigator.clipboard.writeText(JSON.stringify(doc, null, 2));
        },
      },
      {
        name: 'Duplicate',
        iconName: 'lucide:copyPlus',
        action: async () => {
          const { _id, ...docWithoutId } = doc;
          const newDoc = { ...docWithoutId, createdAt: new Date().toISOString() };
          try {
            const insertedId = await apiService.insertDocument(
              this.databaseName,
              this.collectionName,
              newDoc
            );
            await this.loadDocuments();
            this.selectedId = insertedId;
            this.dispatchEvent(
              new CustomEvent('document-selected', {
                detail: { documentId: insertedId },
                bubbles: true,
                composed: true,
              })
            );
          } catch (err) {
            console.error('Error duplicating document:', err);
          }
        },
      },
      { divider: true },
      {
        name: 'Delete',
        iconName: 'lucide:trash2',
        action: async () => {
          if (confirm(`Delete document "${docId}"?`)) {
            const result = await apiService.deleteDocument(
              this.databaseName,
              this.collectionName,
              docId
            );
            if (result.success) {
              await this.loadDocuments();
              if (this.selectedId === docId) {
                this.selectedId = '';
              }
            }
          }
        },
      },
    ]);
  }

  render() {
    const startRecord = (this.page - 1) * this.pageSize + 1;
    const endRecord = Math.min(this.page * this.pageSize, this.total);

    return html`
      <div class="documents-container">
        <div class="filter-bar">
          <input
            type="text"
            class="filter-input"
            placeholder='Filter: {"field": "value"}'
            .value=${this.filterText}
            @input=${this.handleFilterInput}
            @keypress=${this.handleKeyPress}
          />
          <button class="filter-btn" @click=${this.handleFilterSubmit}>Apply</button>
        </div>

        <div class="actions-bar">
          <button class="action-btn" @click=${this.handleInsertNew}>+ Insert Document</button>
        </div>

        <div class="documents-list">
          ${this.loading
            ? html`<div class="loading-state">Loading...</div>`
            : this.documents.length === 0
              ? html`<div class="empty-state">No documents found</div>`
              : this.documents.map(
                  (doc) => html`
                    <div
                      class="document-row ${this.selectedId === doc._id ? 'selected' : ''}"
                      @click=${() => this.selectDocument(doc)}
                      @contextmenu=${(e: MouseEvent) => this.handleDocumentContextMenu(e, doc)}
                    >
                      <div class="document-id">_id: ${doc._id}</div>
                      <div class="document-preview">${this.getDocumentPreview(doc)}</div>
                    </div>
                  `
                )}
        </div>

        ${this.total > 0
          ? html`
              <div class="pagination">
                <div class="pagination-info">
                  Showing ${startRecord}-${endRecord} of ${this.total}
                </div>
                <div class="pagination-controls">
                  <button
                    class="page-btn"
                    ?disabled=${this.page <= 1}
                    @click=${() => this.goToPage(this.page - 1)}
                  >
                    Previous
                  </button>
                  <button
                    class="page-btn"
                    ?disabled=${this.page >= this.totalPages}
                    @click=${() => this.goToPage(this.page + 1)}
                  >
                    Next
                  </button>
                </div>
              </div>
            `
          : ''}
      </div>
    `;
  }
}
