/**
 * Time Machine - Advanced History with Timeline, Branching & Merging
 * Git-like version control for image editing
 */

class TimeMachine {
  constructor() {
    this.branches = {
      main: {
        name: 'main',
        commits: [],
        head: -1,
        color: '#4a9eff'
      }
    };
    this.currentBranch = 'main';
    this.maxCommits = 100;
    this.isApplying = false;
    this.compareMode = false;
    this.compareCommits = { left: null, right: null };
  }

  /**
   * Commit current state (like git commit)
   */
  commit(action, data) {
    if (this.isApplying) return;

    const branch = this.branches[this.currentBranch];
    
    // Remove any commits after current head (when making new changes after jumping back)
    branch.commits = branch.commits.slice(0, branch.head + 1);

    // Create commit
    const commit = {
      id: this.generateCommitId(),
      branch: this.currentBranch,
      action: action,
      timestamp: Date.now(),
      timeString: new Date().toLocaleTimeString(),
      dateString: new Date().toLocaleDateString(),
      data: this.cloneData(data),
      parent: branch.head >= 0 ? branch.commits[branch.head].id : null
    };

    // Add to branch
    branch.commits.push(commit);
    branch.head++;

    // Limit commits
    if (branch.commits.length > this.maxCommits) {
      branch.commits.shift();
      branch.head--;
    }

    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Committed: ${action} on ${this.currentBranch}`);
  }

  /**
   * Checkout to specific commit
   */
  checkout(commitId) {
    const { branch, index } = this.findCommit(commitId);
    if (!branch) {
      console.error('[Time Machine] Commit not found:', commitId);
      return false;
    }

    const commit = branch.commits[index];
    
    this.isApplying = true;
    this.applyCommit(commit);
    this.isApplying = false;

    // Update branch head
    this.branches[branch.name].head = index;
    this.currentBranch = branch.name;

    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Checked out: ${commitId}`);
    return true;
  }

  /**
   * Create new branch from current commit
   */
  createBranch(branchName, fromCommitId = null) {
    if (this.branches[branchName]) {
      console.error('[Time Machine] Branch already exists:', branchName);
      return false;
    }

    const sourceCommitId = fromCommitId || this.getCurrentCommit()?.id;
    if (!sourceCommitId) {
      console.error('[Time Machine] No commit to branch from');
      return false;
    }

    const { branch: sourceBranch, index } = this.findCommit(sourceCommitId);
    if (!sourceBranch) {
      console.error('[Time Machine] Source commit not found');
      return false;
    }

    // Copy commits up to the branch point
    const commits = sourceBranch.commits.slice(0, index + 1).map(c => ({
      ...c,
      branch: branchName
    }));

    // Create new branch
    this.branches[branchName] = {
      name: branchName,
      commits: commits,
      head: commits.length - 1,
      color: this.generateBranchColor(),
      parent: this.currentBranch,
      branchPoint: sourceCommitId
    };

    this.currentBranch = branchName;
    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Created branch: ${branchName} from ${sourceCommitId}`);
    return true;
  }

  /**
   * Merge branch into current branch
   */
  async mergeBranch(sourceBranchName) {
    if (!this.branches[sourceBranchName]) {
      console.error('[Time Machine] Source branch not found:', sourceBranchName);
      return false;
    }

    const sourceBranch = this.branches[sourceBranchName];
    const targetBranch = this.branches[this.currentBranch];

    // Get the latest commit from source branch
    const sourceCommit = sourceBranch.commits[sourceBranch.head];
    
    if (!sourceCommit) {
      console.error('[Time Machine] No commits in source branch');
      return false;
    }

    // Create merge commit
    const mergeCommit = {
      id: this.generateCommitId(),
      branch: this.currentBranch,
      action: `Merge ${sourceBranchName} → ${this.currentBranch}`,
      timestamp: Date.now(),
      timeString: new Date().toLocaleTimeString(),
      dateString: new Date().toLocaleDateString(),
      data: this.cloneData(sourceCommit.data),
      parent: targetBranch.commits[targetBranch.head]?.id || null,
      mergeParent: sourceCommit.id,
      isMerge: true
    };

    // Add merge commit
    targetBranch.commits.push(mergeCommit);
    targetBranch.head++;

    // Apply the merged state
    this.isApplying = true;
    this.applyCommit(mergeCommit);
    this.isApplying = false;

    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Merged ${sourceBranchName} into ${this.currentBranch}`);
    return true;
  }

  /**
   * Delete branch
   */
  deleteBranch(branchName) {
    if (branchName === 'main') {
      console.error('[Time Machine] Cannot delete main branch');
      return false;
    }

    if (branchName === this.currentBranch) {
      console.error('[Time Machine] Cannot delete current branch');
      return false;
    }

    if (!this.branches[branchName]) {
      console.error('[Time Machine] Branch not found:', branchName);
      return false;
    }

    delete this.branches[branchName];
    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Deleted branch: ${branchName}`);
    return true;
  }

  /**
   * Switch to different branch
   */
  switchBranch(branchName) {
    if (!this.branches[branchName]) {
      console.error('[Time Machine] Branch not found:', branchName);
      return false;
    }

    const branch = this.branches[branchName];
    if (branch.head >= 0) {
      const commit = branch.commits[branch.head];
      this.isApplying = true;
      this.applyCommit(commit);
      this.isApplying = false;
    }

    this.currentBranch = branchName;
    this.updateUI();
    this.saveToStorage();

    console.log(`[Time Machine] Switched to branch: ${branchName}`);
    return true;
  }

  /**
   * Enable compare mode
   */
  enableCompareMode(commitId1, commitId2) {
    this.compareMode = true;
    this.compareCommits.left = commitId1;
    this.compareCommits.right = commitId2;
    this.updateUI();
    this.renderCompareView();
  }

  /**
   * Disable compare mode
   */
  disableCompareMode() {
    this.compareMode = false;
    this.compareCommits = { left: null, right: null };
    this.updateUI();
    this.hideCompareView();
  }

  /**
   * Render compare view (split screen)
   */
  renderCompareView() {
    const { left, right } = this.compareCommits;
    if (!left || !right) return;

    const leftCommit = this.findCommit(left);
    const rightCommit = this.findCommit(right);

    if (!leftCommit.branch || !rightCommit.branch) return;

    // Create compare overlay
    const overlay = document.createElement('div');
    overlay.id = 'compareOverlay';
    overlay.className = 'compare-overlay';
    overlay.innerHTML = `
      <div class="compare-header">
        <h3>📊 Compare Mode</h3>
        <button class="compare-close" onclick="timeMachine.disableCompareMode()">×</button>
      </div>
      <div class="compare-content">
        <div class="compare-side">
          <div class="compare-label">
            ${leftCommit.branch.commits[leftCommit.index].action}
            <br>
            <small>${leftCommit.branch.commits[leftCommit.index].timeString}</small>
          </div>
          <img id="compareLeft" src="" alt="Left">
        </div>
        <div class="compare-divider"></div>
        <div class="compare-side">
          <div class="compare-label">
            ${rightCommit.branch.commits[rightCommit.index].action}
            <br>
            <small>${rightCommit.branch.commits[rightCommit.index].timeString}</small>
          </div>
          <img id="compareRight" src="" alt="Right">
        </div>
      </div>
    `;

    document.body.appendChild(overlay);

    // Load images
    const leftImg = document.getElementById('compareLeft');
    const rightImg = document.getElementById('compareRight');
    
    leftImg.src = leftCommit.branch.commits[leftCommit.index].data.imageData;
    rightImg.src = rightCommit.branch.commits[rightCommit.index].data.imageData;
  }

  /**
   * Hide compare view
   */
  hideCompareView() {
    const overlay = document.getElementById('compareOverlay');
    if (overlay) {
      overlay.remove();
    }
  }

  /**
   * Get current commit
   */
  getCurrentCommit() {
    const branch = this.branches[this.currentBranch];
    if (branch.head < 0) return null;
    return branch.commits[branch.head];
  }

  /**
   * Get all commits across all branches (for timeline view)
   */
  getAllCommits() {
    const allCommits = [];
    
    Object.values(this.branches).forEach(branch => {
      branch.commits.forEach(commit => {
        allCommits.push({
          ...commit,
          branchName: branch.name,
          branchColor: branch.color
        });
      });
    });

    // Sort by timestamp
    allCommits.sort((a, b) => a.timestamp - b.timestamp);
    
    return allCommits;
  }

  /**
   * Find commit by ID
   */
  findCommit(commitId) {
    for (const [branchName, branch] of Object.entries(this.branches)) {
      const index = branch.commits.findIndex(c => c.id === commitId);
      if (index !== -1) {
        return { branch, index };
      }
    }
    return { branch: null, index: -1 };
  }

  /**
   * Apply commit data
   */
  applyCommit(commit) {
    if (!commit || !commit.data) return;

    const data = commit.data;

    // Restore image
    if (data.imageData && window.previewImage) {
      window.previewImage.src = data.imageData;
    }

    // Restore adjustments
    if (data.adjustments && window.adjustments) {
      Object.assign(window.adjustments, data.adjustments);
      if (typeof updateAllControls === 'function') {
        updateAllControls(data.adjustments);
      }
    }

    // Restore states
    if (data.states) {
      if (data.states.bwEnabled !== undefined && window.bwEnabled !== undefined) {
        window.bwEnabled = data.states.bwEnabled;
        const bwToggle = document.getElementById('bwToggle');
        if (bwToggle) bwToggle.checked = data.states.bwEnabled;
      }
    }

    // Restore CSS filter
    if (data.cssFilter !== undefined && window.previewImage) {
      window.previewImage.style.filter = data.cssFilter;
    }

    // Recalculate histogram
    setTimeout(() => {
      if (typeof calculateHistogram === 'function') {
        calculateHistogram();
      }
    }, 100);
  }

  /**
   * Clone data
   */
  cloneData(data) {
    if (!data) return null;
    return JSON.parse(JSON.stringify(data));
  }

  /**
   * Generate commit ID
   */
  generateCommitId() {
    return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
  }

  /**
   * Generate branch color
   */
  generateBranchColor() {
    const colors = [
      '#4a9eff', '#f59e0b', '#10b981', '#ef4444', 
      '#8b5cf6', '#ec4899', '#06b6d4', '#84cc16'
    ];
    const usedColors = Object.values(this.branches).map(b => b.color);
    const available = colors.filter(c => !usedColors.includes(c));
    return available[0] || colors[Math.floor(Math.random() * colors.length)];
  }

  /**
   * Update UI
   */
  updateUI() {
    this.renderTimeline();
    this.renderBranchSelector();
    this.updateButtons();
  }

  /**
   * Render timeline visualization
   */
  renderTimeline() {
    const container = document.getElementById('timelineContainer');
    if (!container) return;

    const allCommits = this.getAllCommits();
    
    if (allCommits.length === 0) {
      container.innerHTML = '<div class="timeline-empty">No commits yet</div>';
      return;
    }

    // Group by date
    const groupedByDate = {};
    allCommits.forEach(commit => {
      if (!groupedByDate[commit.dateString]) {
        groupedByDate[commit.dateString] = [];
      }
      groupedByDate[commit.dateString].push(commit);
    });

    let html = '';
    
    Object.entries(groupedByDate).forEach(([date, commits]) => {
      html += `<div class="timeline-date">${date}</div>`;
      
      commits.forEach(commit => {
        const isActive = commit.id === this.getCurrentCommit()?.id;
        const isMerge = commit.isMerge;
        
        html += `
          <div class="timeline-commit ${isActive ? 'active' : ''} ${isMerge ? 'merge' : ''}"
               data-commit-id="${commit.id}"
               style="border-left-color: ${commit.branchColor}">
            <div class="timeline-commit-header">
              <span class="timeline-branch" style="background: ${commit.branchColor}">
                ${commit.branchName}
              </span>
              <span class="timeline-time">${commit.timeString}</span>
            </div>
            <div class="timeline-commit-action">
              ${isMerge ? '🔀 ' : ''}${commit.action}
            </div>
            <div class="timeline-commit-actions">
              <button onclick="timeMachine.checkout('${commit.id}')" class="timeline-btn">
                Checkout
              </button>
              <button onclick="timeMachine.showCommitMenu('${commit.id}')" class="timeline-btn">
                ⋮
              </button>
            </div>
            ${isActive ? '<div class="timeline-current">← Current</div>' : ''}
          </div>
        `;
      });
    });

    container.innerHTML = html;
  }

  /**
   * Render branch selector
   */
  renderBranchSelector() {
    const selector = document.getElementById('branchSelector');
    if (!selector) return;

    let html = '<option value="">Select branch...</option>';
    
    Object.values(this.branches).forEach(branch => {
      const selected = branch.name === this.currentBranch ? 'selected' : '';
      const commitCount = branch.commits.length;
      html += `
        <option value="${branch.name}" ${selected}>
          ${branch.name} (${commitCount} commits)
        </option>
      `;
    });

    selector.innerHTML = html;
  }

  /**
   * Update buttons
   */
  updateButtons() {
    const branch = this.branches[this.currentBranch];
    
    // Can go back?
    const canGoBack = branch.head > 0;
    const backBtn = document.getElementById('timelineBackBtn');
    if (backBtn) backBtn.disabled = !canGoBack;

    // Can go forward?
    const canGoForward = branch.head < branch.commits.length - 1;
    const forwardBtn = document.getElementById('timelineForwardBtn');
    if (forwardBtn) forwardBtn.disabled = !canGoForward;
  }

  /**
   * Show commit context menu
   */
  showCommitMenu(commitId) {
    const { branch, index } = this.findCommit(commitId);
    if (!branch) return;

    const commit = branch.commits[index];
    
    if (typeof Swal === 'undefined') {
      const action = prompt('Actions: branch, compare, delete');
      if (action === 'branch') {
        const name = prompt('Branch name:');
        if (name) this.createBranch(name, commitId);
      }
      return;
    }

    Swal.fire({
      title: commit.action,
      html: `
        <div style="text-align: left; margin: 20px 0;">
          <p><strong>Branch:</strong> ${commit.branch}</p>
          <p><strong>Time:</strong> ${commit.timeString}</p>
          <p><strong>ID:</strong> ${commit.id.substr(0, 8)}...</p>
        </div>
      `,
      showCancelButton: true,
      showDenyButton: true,
      confirmButtonText: '🌿 Create Branch',
      denyButtonText: '📊 Compare',
      cancelButtonText: 'Close'
    }).then((result) => {
      if (result.isConfirmed) {
        this.promptCreateBranch(commitId);
      } else if (result.isDenied) {
        this.promptCompare(commitId);
      }
    });
  }

  /**
   * Prompt create branch
   */
  async promptCreateBranch(fromCommitId) {
    if (typeof Swal === 'undefined') {
      const name = prompt('Branch name:');
      if (name) this.createBranch(name, fromCommitId);
      return;
    }

    const result = await Swal.fire({
      title: '🌿 Create Branch',
      input: 'text',
      inputLabel: 'Branch name',
      inputPlaceholder: 'experiment-1',
      showCancelButton: true,
      inputValidator: (value) => {
        if (!value) return 'Please enter a branch name';
        if (this.branches[value]) return 'Branch already exists';
      }
    });

    if (result.isConfirmed && result.value) {
      this.createBranch(result.value, fromCommitId);
      showMessage(`✓ Created branch: ${result.value}`, 'success');
    }
  }

  /**
   * Prompt compare
   */
  async promptCompare(commitId1) {
    const allCommits = this.getAllCommits();
    
    if (typeof Swal === 'undefined') {
      alert('Compare mode requires SweetAlert2');
      return;
    }

    const options = {};
    allCommits.forEach(c => {
      options[c.id] = `${c.action} (${c.timeString})`;
    });

    const result = await Swal.fire({
      title: '📊 Compare With',
      input: 'select',
      inputOptions: options,
      inputPlaceholder: 'Select commit to compare',
      showCancelButton: true
    });

    if (result.isConfirmed && result.value) {
      this.enableCompareMode(commitId1, result.value);
    }
  }

  /**
   * Go back one commit
   */
  goBack() {
    const branch = this.branches[this.currentBranch];
    if (branch.head > 0) {
      const commit = branch.commits[branch.head - 1];
      this.checkout(commit.id);
    }
  }

  /**
   * Go forward one commit
   */
  goForward() {
    const branch = this.branches[this.currentBranch];
    if (branch.head < branch.commits.length - 1) {
      const commit = branch.commits[branch.head + 1];
      this.checkout(commit.id);
    }
  }

  /**
   * Save to localStorage
   */
  saveToStorage() {
    try {
      const data = {
        branches: this.branches,
        currentBranch: this.currentBranch
      };
      localStorage.setItem('timeMachine', JSON.stringify(data));
    } catch (error) {
      console.error('[Time Machine] Failed to save:', error);
    }
  }

  /**
   * Load from localStorage
   */
  loadFromStorage() {
    try {
      const stored = localStorage.getItem('timeMachine');
      if (stored) {
        const data = JSON.parse(stored);
        this.branches = data.branches;
        this.currentBranch = data.currentBranch;
        this.updateUI();
        console.log('[Time Machine] Loaded from storage');
      }
    } catch (error) {
      console.error('[Time Machine] Failed to load:', error);
    }
  }

  /**
   * Clear all history
   */
  clear() {
    this.branches = {
      main: {
        name: 'main',
        commits: [],
        head: -1,
        color: '#4a9eff'
      }
    };
    this.currentBranch = 'main';
    this.updateUI();
    this.saveToStorage();
    console.log('[Time Machine] Cleared all history');
  }

  /**
   * Export timeline
   */
  exportTimeline() {
    return {
      version: '1.0',
      exported: new Date().toISOString(),
      branches: this.branches,
      currentBranch: this.currentBranch
    };
  }

  /**
   * Import timeline
   */
  importTimeline(data) {
    if (!data || !data.branches) return false;
    
    this.branches = data.branches;
    this.currentBranch = data.currentBranch || 'main';
    this.updateUI();
    this.saveToStorage();
    
    return true;
  }
}

// Create global instance
window.timeMachine = new TimeMachine();

// Load from storage on init
window.timeMachine.loadFromStorage();

// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
  // Alt + Left Arrow: Go back
  if (e.altKey && e.key === 'ArrowLeft') {
    e.preventDefault();
    window.timeMachine.goBack();
  }
  // Alt + Right Arrow: Go forward
  else if (e.altKey && e.key === 'ArrowRight') {
    e.preventDefault();
    window.timeMachine.goForward();
  }
});

console.log('[Time Machine] Initialized ✓');
console.log('[Time Machine] Shortcuts: Alt+← (back), Alt+→ (forward)');
