import { DeesElement, customElement, html, css, property, state, type TemplateResult } from '@design.estate/dees-element';
import { RecorderService } from '../services/recorder.service.js';
import type { WccDashboard } from './wcc-dashboard.js';

@customElement('wcc-recording-panel')
export class WccRecordingPanel extends DeesElement {
  // External configuration
  @property({ attribute: false })
  accessor dashboardRef: WccDashboard;

  // Panel state
  @state()
  accessor panelState: 'options' | 'recording' | 'preview' = 'options';

  // Recording options
  @state()
  accessor recordingMode: 'viewport' | 'screen' = 'viewport';

  @state()
  accessor audioEnabled: boolean = false;

  @state()
  accessor selectedMicrophoneId: string = '';

  @state()
  accessor availableMicrophones: MediaDeviceInfo[] = [];

  @state()
  accessor audioLevel: number = 0;

  // Recording state
  @state()
  accessor recordingDuration: number = 0;

  // Preview/trim state
  @state()
  accessor previewVideoUrl: string = '';

  @state()
  accessor trimStart: number = 0;

  @state()
  accessor trimEnd: number = 0;

  @state()
  accessor videoDuration: number = 0;

  @state()
  accessor isDraggingTrim: 'start' | 'end' | null = null;

  @state()
  accessor isExporting: boolean = false;

  // Service instance
  private recorderService: RecorderService;

  constructor() {
    super();
    this.recorderService = new RecorderService({
      onDurationUpdate: (duration) => {
        this.recordingDuration = duration;
        this.dispatchEvent(new CustomEvent('duration-update', {
          detail: { duration },
          bubbles: true,
          composed: true
        }));
      },
      onRecordingComplete: (blob) => {
        this.handleRecordingComplete(blob);
      },
      onAudioLevelUpdate: (level) => {
        this.audioLevel = level;
      },
      onStreamEnded: () => {
        this.stopRecording();
      }
    });
  }

  public static styles = [
    css`
      :host {
        /* CSS Variables */
        --background: #0a0a0a;
        --foreground: #e5e5e5;
        --input: #141414;
        --primary: #3b82f6;
        --border: rgba(255, 255, 255, 0.06);
        --radius-sm: 2px;
        --radius-md: 4px;
        --radius-lg: 6px;
      }

      /* Recording Options Panel */
      .recording-options-panel {
        position: fixed;
        right: 16px;
        bottom: 116px;
        width: 360px;
        background: #0c0c0c;
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: var(--radius-md);
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
        z-index: 1000;
        overflow: hidden;
        font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
      }

      .recording-options-header {
        padding: 0.75rem 1rem;
        background: rgba(255, 255, 255, 0.02);
        border-bottom: 1px solid rgba(255, 255, 255, 0.05);
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .recording-options-title {
        font-size: 0.8rem;
        font-weight: 500;
        color: #ccc;
      }

      .recording-options-close {
        width: 24px;
        height: 24px;
        background: transparent;
        border: none;
        color: #666;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: var(--radius-sm);
        transition: all 0.15s ease;
      }

      .recording-options-close:hover {
        background: rgba(255, 255, 255, 0.05);
        color: #999;
      }

      .recording-options-content {
        padding: 1rem;
      }

      .recording-option-group {
        margin-bottom: 1rem;
      }

      .recording-option-group:last-child {
        margin-bottom: 0;
      }

      .recording-option-label {
        font-size: 0.7rem;
        font-weight: 500;
        color: #888;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        margin-bottom: 0.5rem;
      }

      .recording-mode-buttons {
        display: flex;
        gap: 0.5rem;
      }

      .recording-mode-btn {
        flex: 1;
        padding: 0.6rem 0.75rem;
        background: var(--input);
        border: 1px solid transparent;
        border-radius: var(--radius-sm);
        color: #999;
        font-size: 0.75rem;
        cursor: pointer;
        transition: all 0.15s ease;
        text-align: center;
      }

      .recording-mode-btn:hover {
        border-color: var(--primary);
        color: #ccc;
      }

      .recording-mode-btn.selected {
        background: rgba(59, 130, 246, 0.15);
        border-color: var(--primary);
        color: var(--primary);
      }

      .audio-toggle {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        margin-bottom: 0.75rem;
      }

      .audio-toggle input[type="checkbox"] {
        width: 1rem;
        height: 1rem;
        accent-color: var(--primary);
      }

      .audio-toggle label {
        font-size: 0.75rem;
        color: #999;
        cursor: pointer;
      }

      .microphone-select {
        width: 100%;
        padding: 0.5rem 0.75rem;
        background: var(--input);
        border: 1px solid transparent;
        border-radius: var(--radius-sm);
        color: var(--foreground);
        font-size: 0.75rem;
        outline: none;
        cursor: pointer;
        transition: all 0.15s ease;
      }

      .microphone-select:focus {
        border-color: var(--primary);
      }

      .microphone-select:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }

      .audio-level-container {
        margin-top: 0.75rem;
        padding: 0.5rem;
        background: rgba(255, 255, 255, 0.02);
        border-radius: var(--radius-sm);
      }

      .audio-level-label {
        font-size: 0.65rem;
        color: #666;
        margin-bottom: 0.25rem;
      }

      .audio-level-bar {
        height: 8px;
        background: var(--input);
        border-radius: 4px;
        overflow: hidden;
      }

      .audio-level-fill {
        height: 100%;
        background: linear-gradient(90deg, #22c55e, #84cc16, #eab308);
        border-radius: 4px;
        transition: width 0.1s ease;
      }

      .start-recording-btn {
        width: 100%;
        padding: 0.75rem;
        background: #dc2626;
        border: none;
        border-radius: var(--radius-sm);
        color: white;
        font-size: 0.8rem;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.15s ease;
        margin-top: 1rem;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
      }

      .start-recording-btn:hover {
        background: #b91c1c;
      }

      .start-recording-btn .rec-dot {
        width: 10px;
        height: 10px;
        background: white;
        border-radius: 50%;
      }

      /* Preview Modal */
      .preview-modal-overlay {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.8);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 1000;
        backdrop-filter: blur(4px);
        font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
      }

      .preview-modal {
        width: 90%;
        max-width: 800px;
        background: #0c0c0c;
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: var(--radius-lg);
        overflow: hidden;
        box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
      }

      .preview-modal-header {
        padding: 1rem 1.25rem;
        background: rgba(255, 255, 255, 0.02);
        border-bottom: 1px solid rgba(255, 255, 255, 0.05);
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .preview-modal-title {
        font-size: 0.9rem;
        font-weight: 500;
        color: #ccc;
      }

      .preview-modal-close {
        width: 28px;
        height: 28px;
        background: transparent;
        border: none;
        color: #666;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: var(--radius-sm);
        font-size: 1.2rem;
        transition: all 0.15s ease;
      }

      .preview-modal-close:hover {
        background: rgba(255, 255, 255, 0.05);
        color: #999;
      }

      .preview-modal-content {
        padding: 1.25rem;
      }

      .preview-video-container {
        background: #000;
        border-radius: var(--radius-sm);
        overflow: hidden;
        aspect-ratio: 16 / 9;
      }

      .preview-video {
        width: 100%;
        height: 100%;
        object-fit: contain;
      }

      .preview-modal-actions {
        padding: 1rem 1.25rem;
        border-top: 1px solid rgba(255, 255, 255, 0.05);
        display: flex;
        justify-content: flex-end;
        gap: 0.75rem;
      }

      .preview-btn {
        padding: 0.6rem 1.25rem;
        border-radius: var(--radius-sm);
        font-size: 0.8rem;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.15s ease;
      }

      .preview-btn.secondary {
        background: transparent;
        border: 1px solid rgba(255, 255, 255, 0.1);
        color: #999;
      }

      .preview-btn.secondary:hover {
        border-color: rgba(255, 255, 255, 0.2);
        color: #ccc;
      }

      .preview-btn.primary {
        background: var(--primary);
        border: none;
        color: white;
      }

      .preview-btn.primary:hover {
        background: #2563eb;
      }

      .preview-btn.primary:disabled {
        background: #1e3a5f;
        cursor: not-allowed;
        opacity: 0.7;
      }

      /* Trim Timeline Styles */
      .trim-section {
        margin-top: 1.25rem;
        padding-top: 1.25rem;
        border-top: 1px solid rgba(255, 255, 255, 0.05);
      }

      .trim-section-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 0.75rem;
      }

      .trim-section-title {
        font-size: 0.75rem;
        font-weight: 500;
        color: #888;
        text-transform: uppercase;
        letter-spacing: 0.05em;
      }

      .trim-duration-info {
        font-size: 0.7rem;
        color: #666;
        font-family: 'Consolas', 'Monaco', monospace;
      }

      .trim-timeline {
        position: relative;
        height: 48px;
        background: var(--input);
        border-radius: var(--radius-sm);
        margin-bottom: 0.75rem;
        user-select: none;
      }

      .trim-track {
        position: absolute;
        top: 50%;
        left: 12px;
        right: 12px;
        height: 6px;
        background: #333;
        transform: translateY(-50%);
        border-radius: 3px;
      }

      .trim-selected {
        position: absolute;
        top: 50%;
        height: 6px;
        background: var(--primary);
        transform: translateY(-50%);
        border-radius: 3px;
        pointer-events: none;
      }

      .trim-handle {
        position: absolute;
        top: 50%;
        width: 16px;
        height: 36px;
        background: white;
        border: 2px solid var(--primary);
        border-radius: 4px;
        transform: translate(-50%, -50%);
        cursor: ew-resize;
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background 0.15s ease, transform 0.1s ease;
      }

      .trim-handle:hover {
        background: #e0e0e0;
      }

      .trim-handle:active {
        background: var(--primary);
        transform: translate(-50%, -50%) scale(1.05);
      }

      .trim-handle::before {
        content: '';
        width: 2px;
        height: 16px;
        background: #666;
        border-radius: 1px;
      }

      .trim-handle:active::before {
        background: white;
      }

      .trim-time-labels {
        display: flex;
        justify-content: space-between;
        font-size: 0.65rem;
        color: #666;
        font-family: 'Consolas', 'Monaco', monospace;
        padding: 0 12px;
      }

      .trim-actions {
        display: flex;
        gap: 0.5rem;
        margin-top: 0.75rem;
      }

      .trim-action-btn {
        flex: 1;
        padding: 0.5rem 0.75rem;
        background: var(--input);
        border: 1px solid transparent;
        border-radius: var(--radius-sm);
        color: #999;
        font-size: 0.75rem;
        cursor: pointer;
        transition: all 0.15s ease;
        text-align: center;
      }

      .trim-action-btn:hover {
        border-color: var(--primary);
        color: #ccc;
      }

      .export-spinner {
        display: inline-block;
        width: 14px;
        height: 14px;
        border: 2px solid rgba(255, 255, 255, 0.3);
        border-radius: 50%;
        border-top-color: white;
        animation: spin 0.8s linear infinite;
        margin-right: 0.5rem;
      }

      @keyframes spin {
        to { transform: rotate(360deg); }
      }

    `
  ];

  public render(): TemplateResult {
    if (this.panelState === 'options') {
      return this.renderOptionsPanel();
    } else if (this.panelState === 'preview') {
      return this.renderPreviewModal();
    }
    return html``;
  }

  private renderOptionsPanel(): TemplateResult {
    return html`
      <div class="recording-options-panel">
        <div class="recording-options-header">
          <span class="recording-options-title">Recording Settings</span>
          <button class="recording-options-close" @click=${() => this.close()}>✕</button>
        </div>
        <div class="recording-options-content">
          <div class="recording-option-group">
            <div class="recording-option-label">Record Area</div>
            <div class="recording-mode-buttons">
              <button
                class="recording-mode-btn ${this.recordingMode === 'viewport' ? 'selected' : ''}"
                @click=${() => this.recordingMode = 'viewport'}
              >
                Viewport Only
              </button>
              <button
                class="recording-mode-btn ${this.recordingMode === 'screen' ? 'selected' : ''}"
                @click=${() => this.recordingMode = 'screen'}
              >
                Entire Screen
              </button>
            </div>
          </div>

          <div class="recording-option-group">
            <div class="recording-option-label">Audio</div>
            <div class="audio-toggle">
              <input
                type="checkbox"
                id="audioToggle"
                ?checked=${this.audioEnabled}
                @change=${(e: Event) => this.handleAudioToggle((e.target as HTMLInputElement).checked)}
              />
              <label for="audioToggle">Enable Microphone</label>
            </div>

            ${this.audioEnabled ? html`
              <select
                class="microphone-select"
                .value=${this.selectedMicrophoneId}
                @change=${(e: Event) => this.handleMicrophoneChange((e.target as HTMLSelectElement).value)}
              >
                <option value="">Select Microphone...</option>
                ${this.availableMicrophones.map(mic => html`
                  <option value=${mic.deviceId}>${mic.label || `Microphone ${mic.deviceId.slice(0, 8)}`}</option>
                `)}
              </select>

              ${this.selectedMicrophoneId ? html`
                <div class="audio-level-container">
                  <div class="audio-level-label">Input Level</div>
                  <div class="audio-level-bar">
                    <div class="audio-level-fill" style="width: ${this.audioLevel}%"></div>
                  </div>
                </div>
              ` : null}
            ` : null}
          </div>

          <button class="start-recording-btn" @click=${() => this.startRecording()}>
            <div class="rec-dot"></div>
            Start Recording
          </button>
        </div>
      </div>
    `;
  }

  private renderPreviewModal(): TemplateResult {
    return html`
      <div class="preview-modal-overlay" @click=${(e: Event) => {
        if ((e.target as HTMLElement).classList.contains('preview-modal-overlay')) {
          this.discardRecording();
        }
      }}>
        <div class="preview-modal">
          <div class="preview-modal-header">
            <span class="preview-modal-title">Recording Preview</span>
            <button class="preview-modal-close" @click=${() => this.discardRecording()}>✕</button>
          </div>
          <div class="preview-modal-content">
            <div class="preview-video-container">
              <video
                class="preview-video"
                src=${this.previewVideoUrl}
                controls
                @loadedmetadata=${(e: Event) => this.handleVideoLoaded(e.target as HTMLVideoElement)}
              ></video>
            </div>

            <!-- Trim Section -->
            <div class="trim-section">
              <div class="trim-section-header">
                <span class="trim-section-title">Trim Video</span>
                <span class="trim-duration-info">
                  ${this.formatDuration(Math.floor(this.trimEnd - this.trimStart))}
                  ${this.trimStart > 0 || this.trimEnd < this.videoDuration
                    ? `(trimmed from ${this.formatDuration(Math.floor(this.videoDuration))})`
                    : ''}
                </span>
              </div>

              <div
                class="trim-timeline"
                @mousedown=${(e: MouseEvent) => this.handleTimelineClick(e)}
                @mousemove=${(e: MouseEvent) => this.handleTimelineDrag(e)}
                @mouseup=${() => this.handleTimelineDragEnd()}
                @mouseleave=${() => this.handleTimelineDragEnd()}
              >
                <div class="trim-track"></div>
                <div
                  class="trim-selected"
                  style="left: ${this.getHandlePositionStyle(this.trimStart)}; right: ${this.getHandlePositionFromEndStyle(this.trimEnd)};"
                ></div>
                <div
                  class="trim-handle start-handle"
                  style="left: ${this.getHandlePositionStyle(this.trimStart)};"
                  @mousedown=${(e: MouseEvent) => { e.stopPropagation(); this.isDraggingTrim = 'start'; }}
                ></div>
                <div
                  class="trim-handle end-handle"
                  style="left: ${this.getHandlePositionStyle(this.trimEnd)};"
                  @mousedown=${(e: MouseEvent) => { e.stopPropagation(); this.isDraggingTrim = 'end'; }}
                ></div>
              </div>

              <div class="trim-time-labels">
                <span>${this.formatDuration(Math.floor(this.trimStart))}</span>
                <span>${this.formatDuration(Math.floor(this.trimEnd))}</span>
              </div>

              <div class="trim-actions">
                <button class="trim-action-btn" @click=${() => this.resetTrim()}>
                  Reset Trim
                </button>
                <button class="trim-action-btn" @click=${() => this.previewTrimmedSection()}>
                  Preview Selection
                </button>
              </div>
            </div>

          </div>
          <div class="preview-modal-actions">
            <button class="preview-btn secondary" @click=${() => this.discardRecording()}>Discard</button>
            <button
              class="preview-btn primary"
              ?disabled=${this.isExporting}
              @click=${() => this.downloadRecording()}
            >
              ${this.isExporting ? html`<span class="export-spinner"></span>Exporting...` : 'Download WebM'}
            </button>
          </div>
        </div>
      </div>
    `;
  }

  // ==================== Audio Methods ====================

  private async handleAudioToggle(enabled: boolean): Promise<void> {
    this.audioEnabled = enabled;
    if (enabled) {
      this.availableMicrophones = await this.recorderService.loadMicrophones(true);
      if (this.availableMicrophones.length > 0 && !this.selectedMicrophoneId) {
        this.selectedMicrophoneId = this.availableMicrophones[0].deviceId;
        await this.recorderService.startAudioMonitoring(this.selectedMicrophoneId);
      }
    } else {
      this.recorderService.stopAudioMonitoring();
      this.selectedMicrophoneId = '';
      this.audioLevel = 0;
    }
  }

  private async handleMicrophoneChange(deviceId: string): Promise<void> {
    this.selectedMicrophoneId = deviceId;
    if (deviceId) {
      await this.recorderService.startAudioMonitoring(deviceId);
    } else {
      this.recorderService.stopAudioMonitoring();
      this.audioLevel = 0;
    }
  }

  // ==================== Recording Methods ====================

  private async startRecording(): Promise<void> {
    try {
      let viewportElement: HTMLElement | undefined;
      if (this.recordingMode === 'viewport' && this.dashboardRef) {
        const wccFrame = await this.dashboardRef.wccFrame;
        viewportElement = await wccFrame.getViewportElement();
      }

      await this.recorderService.startRecording({
        mode: this.recordingMode,
        audioDeviceId: this.audioEnabled ? this.selectedMicrophoneId : undefined,
        viewportElement
      });

      this.panelState = 'recording';
      this.dispatchEvent(new CustomEvent('recording-start', {
        bubbles: true,
        composed: true
      }));
    } catch (error) {
      console.error('Failed to start recording:', error);
      this.panelState = 'options';
    }
  }

  public stopRecording(): void {
    this.recorderService.stopRecording();
  }

  private handleRecordingComplete(blob: Blob): void {
    if (this.previewVideoUrl) {
      URL.revokeObjectURL(this.previewVideoUrl);
    }
    this.previewVideoUrl = URL.createObjectURL(blob);
    this.panelState = 'preview';
    this.dispatchEvent(new CustomEvent('recording-stop', {
      bubbles: true,
      composed: true
    }));
  }

  private discardRecording(): void {
    if (this.previewVideoUrl) {
      URL.revokeObjectURL(this.previewVideoUrl);
      this.previewVideoUrl = '';
    }
    this.recorderService.reset();
    this.trimStart = 0;
    this.trimEnd = 0;
    this.videoDuration = 0;
    this.isExporting = false;
    this.recordingDuration = 0;
    this.close();
  }

  private async downloadRecording(): Promise<void> {
    const recordedBlob = this.recorderService.recordedBlob;
    if (!recordedBlob) return;

    this.isExporting = true;

    try {
      let blobToDownload: Blob;

      // Handle trimming if needed
      const needsTrim = this.trimStart > 0.1 || this.trimEnd < this.videoDuration - 0.1;

      if (needsTrim) {
        const video = this.shadowRoot?.querySelector('.preview-video') as HTMLVideoElement;
        if (video) {
          blobToDownload = await this.recorderService.exportTrimmedVideo(video, this.trimStart, this.trimEnd);
        } else {
          blobToDownload = recordedBlob;
        }
      } else {
        blobToDownload = recordedBlob;
      }

      // Trigger download
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
      const filename = `wcctools-recording-${timestamp}.webm`;

      const url = URL.createObjectURL(blobToDownload);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);

      this.discardRecording();
    } catch (error) {
      console.error('Error exporting video:', error);
      this.isExporting = false;
    }
  }

  // ==================== Trim Methods ====================

  private handleVideoLoaded(video: HTMLVideoElement): void {
    // WebM files from MediaRecorder may have Infinity/NaN duration
    // Fall back to the tracked recording duration
    const duration = Number.isFinite(video.duration) ? video.duration : this.recordingDuration;
    this.videoDuration = duration;
    this.trimStart = 0;
    this.trimEnd = duration;
  }

  private formatDuration(seconds: number): string {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }

  private getHandlePositionStyle(time: number): string {
    if (this.videoDuration === 0) return '12px';
    const percentage = time / this.videoDuration;
    // Formula: 12px padding + percentage of remaining width (total - 24px padding)
    // At 0%: 12px (left edge of track)
    // At 100%: calc(100% - 12px) (right edge of track)
    return `calc(12px + ${(percentage * 100).toFixed(2)}% - ${(percentage * 24).toFixed(2)}px)`;
  }

  private getHandlePositionFromEndStyle(time: number): string {
    if (this.videoDuration === 0) return '12px';
    const percentage = time / this.videoDuration;
    const remainingPercentage = 1 - percentage;
    // For CSS 'right' property: distance from right edge
    // At trimEnd = 100%: right = 12px (at right edge of track)
    // At trimEnd = 0%: right = calc(100% - 12px) (at left edge of track)
    return `calc(12px + ${(remainingPercentage * 100).toFixed(2)}% - ${(remainingPercentage * 24).toFixed(2)}px)`;
  }

  private handleTimelineClick(e: MouseEvent): void {
    if (this.isDraggingTrim) return;

    const timeline = e.currentTarget as HTMLElement;
    const rect = timeline.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const percentage = Math.max(0, Math.min(1, (x - 12) / (rect.width - 24)));
    const time = percentage * this.videoDuration;

    const video = this.shadowRoot?.querySelector('.preview-video') as HTMLVideoElement;
    if (video) {
      video.currentTime = time;
    }
  }

  private handleTimelineDrag(e: MouseEvent): void {
    if (!this.isDraggingTrim) return;

    const timeline = e.currentTarget as HTMLElement;
    const rect = timeline.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const percentage = Math.max(0, Math.min(1, (x - 12) / (rect.width - 24)));
    const time = percentage * this.videoDuration;

    const minDuration = 1;

    if (this.isDraggingTrim === 'start') {
      this.trimStart = Math.min(time, this.trimEnd - minDuration);
      this.trimStart = Math.max(0, this.trimStart);
    } else if (this.isDraggingTrim === 'end') {
      this.trimEnd = Math.max(time, this.trimStart + minDuration);
      this.trimEnd = Math.min(this.videoDuration, this.trimEnd);
    }

    const video = this.shadowRoot?.querySelector('.preview-video') as HTMLVideoElement;
    if (video) {
      video.currentTime = this.isDraggingTrim === 'start' ? this.trimStart : this.trimEnd;
    }
  }

  private handleTimelineDragEnd(): void {
    this.isDraggingTrim = null;
  }

  private resetTrim(): void {
    this.trimStart = 0;
    this.trimEnd = this.videoDuration;

    const video = this.shadowRoot?.querySelector('.preview-video') as HTMLVideoElement;
    if (video) {
      video.currentTime = 0;
    }
  }

  private previewTrimmedSection(): void {
    const video = this.shadowRoot?.querySelector('.preview-video') as HTMLVideoElement;
    if (!video) return;

    video.currentTime = this.trimStart;
    video.play();

    const checkTime = () => {
      if (video.currentTime >= this.trimEnd) {
        video.pause();
        video.removeEventListener('timeupdate', checkTime);
      }
    };

    video.addEventListener('timeupdate', checkTime);
  }

  // ==================== Lifecycle ====================

  private close(): void {
    this.recorderService.stopAudioMonitoring();
    this.dispatchEvent(new CustomEvent('close', {
      bubbles: true,
      composed: true
    }));
  }

  async disconnectedCallback(): Promise<void> {
    await super.disconnectedCallback();
    this.recorderService.dispose();
    if (this.previewVideoUrl) {
      URL.revokeObjectURL(this.previewVideoUrl);
    }
  }
}
