import { consume } from "@lit/context";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators.js";

import { ref } from "lit/directives/ref.js";
import type { ContextMixinInterface } from "./ContextMixin.js";
import { efContext } from "./efContext.js";
import { playingContext } from "./playingContext.js";

@customElement("ef-scrubber")
export class EFScrubber extends LitElement {
  static styles = [
    css`
    :host {
      --ef-scrubber-height: 4px;
      --ef-scrubber-background: rgb(209 213 219);
      --ef-scrubber-progress-color: rgb(37 99 235);
      --ef-scrubber-handle-size: 12px;
      display: block;
      width: 100%;
    }
    
    .scrubber {
      width: 100%;
      height: var(--ef-scrubber-height);
      background: var(--ef-scrubber-background);
      position: relative;
      cursor: pointer;
      border-radius: 2px;
    }

    .progress {
      position: absolute;
      height: 100%;
      background: var(--ef-scrubber-progress-color);
      border-radius: 2px;
    }

    .handle {
      position: absolute;
      width: var(--ef-scrubber-handle-size);
      height: var(--ef-scrubber-handle-size);
      background: var(--ef-scrubber-progress-color);
      border-radius: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      cursor: grab;
    }

    /* Add CSS Shadow Parts */
    ::part(scrubber) { }
    ::part(progress) { }
    ::part(handle) { }
    `,
  ];

  @consume({ context: efContext, subscribe: true })
  context?: ContextMixinInterface | null;

  @consume({ context: playingContext, subscribe: true })
  playing = false;

  @state()
  private lastTimeUpdateProgress = 0;

  @state()
  private scrubProgress = 0;

  @state()
  private isDragging = false;

  private scrubberRef?: HTMLElement;

  private updateProgress(e: MouseEvent) {
    if (!this.context || !this.scrubberRef) return;

    const rect = this.scrubberRef.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const progress = Math.max(0, Math.min(1, x / rect.width));

    this.scrubProgress = progress;
    this.context.currentTimeMs =
      progress * (this.context.targetTimegroup?.durationMs ?? 0);
  }

  private boundHandleMouseDown = (e: MouseEvent) => {
    this.isDragging = true;
    e.preventDefault();
    this.updateProgress(e);
  };

  private boundHandleMouseMove = (e: MouseEvent) => {
    if (this.isDragging) {
      this.updateProgress(e);
    }
  };

  private boundHandleMouseUp = () => {
    this.isDragging = false;
  };

  render() {
    const displayProgress = this.isDragging
      ? this.scrubProgress
      : this.lastTimeUpdateProgress;

    return html`
      <div 
        ${ref((el) => {
          this.scrubberRef = el as HTMLElement;
        })}
        part="scrubber"
        class="scrubber"
        @mousedown=${this.boundHandleMouseDown}
      >
        <div class="progress" style="width: ${displayProgress * 100}%"></div>
        <div class="handle" style="left: ${displayProgress * 100}%"></div>
      </div>
    `;
  }

  connectedCallback() {
    super.connectedCallback();
    window.addEventListener("mouseup", this.boundHandleMouseUp);
    window.addEventListener("mousemove", this.boundHandleMouseMove);

    if (this.context) {
      this.context.addEventListener("timeupdate", (e: Event) => {
        this.lastTimeUpdateProgress = (e as CustomEvent).detail.progress;
      });
    }
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    window.removeEventListener("mouseup", this.boundHandleMouseUp);
    window.removeEventListener("mousemove", this.boundHandleMouseMove);
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "ef-scrubber": EFScrubber;
  }
}
