import { CSSResult, html, TemplateResult } from 'lit'
import { ProjectMock } from '@api-client/core/mocking/ProjectMock.js'
import type { IApplication } from '@api-client/core/models/Application.js'
import { HttpProject, type IHttpProject } from '@api-client/core/models/HttpProject.js'
import type { IRequestUiMeta } from '@api-client/core/models/RequestUiMeta.js'
import { Environment } from '@api-client/core/models/Environment.js'
import JsonDiff from '@api-client/json/patch/diff.js'
import * as KeyVal from 'idb-keyval'
import { DemoPage } from '../../../src/demo/DemoPage.js'
import { reactive } from '../../../src/decorators/index.js'
import surfaceStyles from '../../../src/styles/m3/surface.module.js'
// import { WebHttpClientStoreBindings } from '../../../src/bindings/web/WebHttpClientStoreBindings.js'
import HttpProjectRequest from '../../../src/elements/project/HttpProjectRequest.js'
// import { WebProxyBindings } from '../../../src/bindings/web/WebProxyBindings.js'
// import env from '../../env.js'
import '../../../src/define/http-project/http-project-request.js'
import '../../../src/define/http-project/http-project-request-history.js'
import '../../../src/md/button/ui-button.js'

const PROJECT_STORE_KEY = 'demo.project-ui.http-editor.project-data'
const REQUEST_STORE_KEY = 'demo.project-ui.http-editor.request-data'
const UI_STORE_KEY = 'demo.project-ui.http-editor.request-ui'

// const workerUri = new URL('/src/http-client/store/IdbThread.ts', import.meta.url).toString()
const AppInfo: IApplication = { code: 'demo', name: 'Demo', version: '0' }

class ComponentDemoPage extends DemoPage {
  static override get styles(): CSSResult[] {
    return [...DemoPage.styles, surfaceStyles]
  }

  override accessor componentName = 'HTTP project request editor'

  mock = new ProjectMock()

  @reactive() accessor project: HttpProject | undefined

  @reactive() accessor requestKey: string | undefined

  @reactive() accessor ui: IRequestUiMeta = {}

  @reactive() accessor initialized: boolean

  oauth2RedirectUri = 'https://auth.advancedrestclient.com/arc.html'

  oauth2AuthorizationUri = `${window.location.protocol}//${window.location.host}${window.location.pathname}oauth-authorize.html`

  // store = new WebHttpClientStoreBindings(AppInfo, workerUri)

  // http = new WebProxyBindings(AppInfo, `${env.proxyUri}/open`)

  constructor() {
    super()
    this.initialized = false
    this.init()
  }

  async init(): Promise<void> {
    await this.restoreData()
    // await this.store.initialize()
    // await this.http.initialize()
    await this.loadMonaco()
    this.initialized = true
  }

  async restoreData(): Promise<void> {
    const data = await KeyVal.getMany([PROJECT_STORE_KEY, REQUEST_STORE_KEY, UI_STORE_KEY])
    const [project, requestKey, ui] = data
    this.setupProject(project, requestKey)
    this.setupUi(ui)
  }

  setupProject(project?: IHttpProject, requestKey?: string): void {
    let instance: HttpProject
    if (project) {
      instance = new HttpProject(project)
    } else {
      instance = HttpProject.fromName('demo project')
    }
    this.project = instance
    if (requestKey) {
      const value = instance.findRequest(requestKey)
      if (value) {
        this.requestKey = requestKey
        return
      }
    }
    const request = instance.addRequest('http://')
    this.requestKey = request.key
  }

  setupUi(ui?: IRequestUiMeta): void {
    if (ui) {
      this.ui = ui
    } else {
      this.ui = {}
    }
  }

  async storeProject(): Promise<void> {
    await KeyVal.setMany([
      [PROJECT_STORE_KEY, this.project],
      [REQUEST_STORE_KEY, this.requestKey],
    ])
  }

  async storeUi(): Promise<void> {
    await KeyVal.set(UI_STORE_KEY, this.ui)
  }

  handleChange(): void {
    console.log('change in the request')
    this.storeProject()
  }

  handleUiChange(e: Event): void {
    const editor = e.target as HttpProjectRequest
    if (!editor.ui) {
      return
    }
    this.ui = editor.ui
    this.storeUi()
    console.log('ui change', editor.ui)
  }

  addEnvironment(): void {
    const { project } = this
    if (!project) {
      return
    }
    const name = this.mock.lorem.words(2)
    const localEnv = Environment.fromName(name)
    localEnv.addVariable('port', '8000')
    localEnv.addVariable('host', 'localhost')
    localEnv.addServer('http://{host}:{port}/')

    const snapshot = project.toJSON()
    project.addEnvironment(localEnv)
    const compare = project.toJSON()
    const patches = JsonDiff(snapshot, compare)
    const editor = document.querySelector('http-project-request')
    if (editor) {
      patches.forEach((patch) => editor.applyPatch(patch))
    }
    this.storeProject()
  }

  clearEnvironments(): void {
    const { project } = this
    if (!project) {
      return
    }
    const snapshot = project.toJSON()
    const all = project.listEnvironments()
    all.forEach((localEnv) => project.removeEnvironment(localEnv.key))
    const compare = project.toJSON()
    const patches = JsonDiff(snapshot, compare)
    const editor = document.querySelector('http-project-request')
    if (editor) {
      patches.forEach((patch) => editor.applyPatch(patch))
    }
    this.storeProject()
  }

  clearAll(): void {
    const instance = HttpProject.fromName('demo project')
    this.project = instance
    const request = instance.addRequest('http://')
    this.requestKey = request.key
    this.ui = {}
  }

  contentTemplate(): TemplateResult {
    if (!this.initialized) {
      return this.renderLoader()
    }
    return html`
      <a href="./">Back</a>
      ${this.renderDataControl()} ${this.renderComponent()}
    `
  }

  renderLoader(): TemplateResult {
    return html`
      <a href="./">Back</a>
      <div class="screen-loader">
        <p>Loading demo page</p>
        <progress></progress>
      </div>
    `
  }

  renderDataControl(): TemplateResult {
    return html`
      <section class="demo-section">
        <h2 class="title-large">Data control</h2>
        <ui-button color="outlined" @click="${this.addEnvironment}">Add environment</ui-button>
        <ui-button color="outlined" @click="${this.clearEnvironments}">Remove all environments</ui-button>
        <ui-button color="outlined" @click="${this.clearAll}">Clear all data</ui-button>
      </section>
    `
  }

  renderComponent(): TemplateResult {
    return html`
      <section class="demo-section">
        <h2 class="title-large">HTTP request editor</h2>
        <div class="editor-wrapper surface1">
          <http-project-request
            .project="${this.project}"
            .key="${this.requestKey}"
            .ui="${this.ui}"
            .oauth2RedirectUri="${this.oauth2RedirectUri}"
            .oauth2AuthorizationUri="${this.oauth2AuthorizationUri}"
            .appInfo="${AppInfo}"
            @change="${this.handleChange}"
            @uichange="${this.handleUiChange}"
          ></http-project-request>
        </div>
        <div class="editor-wrapper surface1">
          <http-project-request-history
            .project="${this.project && this.project.key}"
            .request="${this.requestKey}"
          ></http-project-request-history>
        </div>
      </section>
    `
  }
}

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