import { html } from 'lit'
import type { FunctionSchema } from '@pawel-up/jexl/schemas/types.js'
import reactive from '../../../src/decorators/reactive.js'
import { DemoPage } from '../../../src/demo/DemoPage.js'
import type {
  Suggestion,
  FunctionInsertEvent,
  SuggestionInsertEvent,
} from '../../../src/elements/code-editor/code-editor.js'
import '../../../src/elements/code-editor/code-editor.js'
import { stringLibrarySchema } from '@pawel-up/jexl/schemas/string.schema.js'
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/array.schema.js'
import { dateLibrarySchema } from '@pawel-up/jexl/schemas/date.schema.js'
import { mathLibrarySchema } from '@pawel-up/jexl/schemas/math.schema.js'

class CodeEditorDemo extends DemoPage {
  override accessor componentName = 'Code Editor'

  @reactive()
  private accessor output = ''

  @reactive()
  private accessor editorValue = [
    '// Start typing function names or {{ mentions }}',
    '',
    '"Hello {{John}}! Can you help with the " + upper() + " function?"',
  ].join('\n')

  private suggestions: Suggestion[] = [
    {
      id: 'user-john',
      label: 'John',
      description: 'Software Engineer',
      suffix: 'Engineering',
      data: { role: 'developer', department: 'engineering' },
    },
    {
      id: 'user-jane',
      label: 'Jane',
      description: 'Product Manager',
      suffix: 'Product',
      data: { role: 'manager', department: 'product' },
    },
    {
      id: 'admin-system',
      label: 'System',
      description: 'System Administrator',
      suffix: 'Admin',
      data: { role: 'admin', department: 'infrastructure' },
    },
  ]

  functions: FunctionSchema[] = []

  constructor() {
    super()

    // Initialize function schemas
    this.functions = this.createFunctionSchema()
  }

  /**
   * Creates a schema for the code-editor functions.
   * This method is responsible for defining the functions that can be used in the formula,
   * given the current data type.
   */
  createFunctionSchema(): FunctionSchema[] {
    const result: FunctionSchema[] = []

    for (const func of Object.values(stringLibrarySchema.functions)) {
      result.push(func)
    }

    for (const func of Object.values(arrayLibrarySchema.functions)) {
      result.push(func)
    }

    for (const func of Object.values(dateLibrarySchema.functions)) {
      result.push(func)
    }

    for (const func of Object.values(mathLibrarySchema.functions)) {
      result.push(func)
    }

    return result
  }

  private handleFunctionInsert(event: CustomEvent<FunctionInsertEvent>): void {
    const { functionSchema, position } = event.detail
    this.output = `Function inserted: ${functionSchema.name} at position ${position}`
  }

  private handleSuggestionInsert(event: CustomEvent<SuggestionInsertEvent>): void {
    const { suggestion, position } = event.detail
    this.output = `Suggestion inserted: ${suggestion.label} at position ${position}`
  }

  private handleInput(event: Event): void {
    const target = event.target as HTMLElement & { value: string }
    this.editorValue = target.value
  }

  private handleFunctionDocumentation(event: CustomEvent<{ functionSchema: FunctionSchema }>): void {
    const { functionSchema } = event.detail
    this.output = `Function documentation requested for: ${functionSchema.name}`
    console.log('Function documentation:', functionSchema)
  }

  private handleChange(event: Event): void {
    const target = event.target as HTMLElement & { value: string }
    this.output = `Editor content changed: ${target.value}`
    console.log('Editor change:', target.value)
  }

  contentTemplate() {
    return html`
      <a href="../">Back</a>

      <section class="demo-section">
        <h2 class="display-large">Basic Code Editor</h2>
        <p>A CodeMirror 6 based editor with function autocomplete and suggestion pills.</p>

        <code-editor
          label="Code Editor"
          supportingtext="Type function names or {{fnName}} to see autocomplete"
          .value=${this.editorValue}
          .functionSchemas=${this.functions}
          .suggestions=${this.suggestions}
          @functioninsert=${this.handleFunctionInsert}
          @suggestioninsert=${this.handleSuggestionInsert}
          @input=${this.handleInput}
          @change=${this.handleChange}
          showdocumentation
          @docsrequest="${this.handleFunctionDocumentation}"
        ></code-editor>

        ${this.output ? html`<p><strong>Output:</strong> ${this.output}</p>` : ''}
      </section>

      <section class="demo-section">
        <h2 class="display-large">Disabled State</h2>
        <p>A disabled editor for read-only content.</p>

        <code-editor
          label="Disabled Editor"
          supportingtext="This editor is disabled"
          .value=${'// This editor is disabled\nconst readOnly = true'}
          .functionSchemas=${this.functions}
          .suggestions=${this.suggestions}
          disabled
        ></code-editor>
      </section>

      <section class="demo-section">
        <h2 class="display-large">Error State</h2>
        <p>An editor in error state.</p>

        <code-editor
          label="Error Editor"
          supportingtext="This editor has an error"
          .value=${'// This editor has an error\nconst invalid = true'}
          .functionSchemas=${this.functions}
          .suggestions=${this.suggestions}
          invalid
        ></code-editor>
      </section>
    `
  }
}

const instance = new CodeEditorDemo()
instance.render()
