import { Component, AfterViewInit, ViewChild } from '@angular/core';
import * as ace from 'ace-builds';
import * as Diff from 'diff';
const Range = ace.require('ace/range').Range;

@Component({
  selector: 'app-file-comparison',
  templateUrl: './file-comparison.component.html',
  styleUrls: ['./file-comparison.component.css']
})
export class FileComparisonComponent implements AfterViewInit {
  @ViewChild('editorLeft', { static: true }) editorLeft: any;
  @ViewChild('editorRight', { static: true }) editorRight: any;
  leftEditor: ace.Ace.Editor;
  rightEditor: ace.Ace.Editor;
  editorOptions: any;


  
  getMarkers(originalText: string, modifiedText: string) {
    const markers = [];
    const originalLines = originalText.split('\n');
    const modifiedLines = modifiedText.split('\n');

    originalLines.forEach((line, index) => {
        if (modifiedLines[index] !== line) {
            markers.push({
                startRow: index,
                endRow: index,
                className: 'word-changed',
            });
        }
    });

    modifiedLines.slice(originalLines.length).forEach((_, index) => {
        markers.push({
            startRow: originalLines.length + index,
            endRow: originalLines.length + index,
            className: 'new-line',
        });
    });

    return markers;
}

// Apply markers to the ACE Editor


  ngAfterViewInit(): void {
    this.initializeEditor('editorLeft', this.editorLeft);
    this.initializeEditor('editorRight', this.editorRight);
    this.loadExampleFiles();
  }

  initializeEditor(elementId: string, editor: any): void {
    const editorInstance = ace.edit(elementId);
   // editorInstance.setTheme('ace/theme/monokai');
    editorInstance.session.setMode('ace/mode/xml'); // Set the mode to XML for better syntax highlighting
    editorInstance.session.setUseWrapMode(true);
    editorInstance.setShowPrintMargin(false);
    editorInstance.setOption('maxLines', Infinity);
    editorInstance.setOption('minLines', 20);    

    if (elementId === 'editorLeft') {
      this.leftEditor = editorInstance;
    } else {
      this.rightEditor = editorInstance;
    }
  }

  loadExampleFiles(): void {
    const fileLeft = `<catalog>
  <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
  </book>
  </catalog>`;
    const fileRight = `<catalog>
  <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guides</title>
      <genre>Computers</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
  </book>
  </catalog>`;

    this.leftEditor.setValue(fileLeft, -1);
    this.rightEditor.setValue(fileRight, -1);

  //  this.leftEditor.getSession().setMarkers(this.getMarkers(this.fileLeft, this.fileRight));

    // Call the comparison method
   this.highlightDifferences();

   //this.highlightModifiedContent();
  }


  highlightModifiedContent(): void {
    // Clear existing markers
    //this.previewEditor.session.clearMarkers();
  
    const originalLines = this.leftEditor.getValue().split('\n');
    const previewLines = this.rightEditor.getValue().split('\n');
  
    // Loop through preview lines
    for (let i = 0; i < previewLines.length; i++) {
      const originalLine = originalLines[i] || ''; // Handle undefined for originalLines
      const previewLine = previewLines[i];
  
      if (originalLine !== previewLine) {
        // Find start of difference
        let startCol = 0;
        while (
          startCol < originalLine.length &&
          startCol < previewLine.length &&
          originalLine[startCol] === previewLine[startCol]
        ) {
          startCol++;
        }
  
        // Find end of difference
        let endColPreview = previewLine.length - 1;
        while (
          endColPreview >= startCol &&
          originalLine[endColPreview] === previewLine[endColPreview]
        ) {
          endColPreview--;
        }
  
        // Add marker for modified content
        const range = new Range(i, startCol, i, endColPreview + 1);
        this.rightEditor.session.addMarker(range, 'highlight', 'text');
      }
    }
  }
  

  highlightDifferences(): void {
    const leftContent = this.leftEditor.getValue();
    const rightContent = this.rightEditor.getValue();

    const diff = Diff.diffLines(leftContent, rightContent);

    // Clear any previous markers
  
    this.leftEditor.getSession().clearAnnotations();
    this.rightEditor.getSession().clearAnnotations();

    // Track rows for left and right editors
    let leftRow = 0;
    let rightRow = 0;

    diff.forEach((part) => {
      const lines = part.value.split('\n').slice(0, -1); // Remove empty last line from split

      if (part.added) {
        // Highlight added lines in the right editor
        lines.forEach((line, index) => {
          this.rightEditor.getSession().addMarker(
            new ace.Range(rightRow, 0, rightRow, 1),
            'ace_added_line',
            'fullLine'
          );

          // Highlight word differences if there are changes within the line
          if (index === 0 && lines.length === 1 && line.trim() !== '') {
             this.highlightWordDifferences('', line, rightRow, this.rightEditor);
          }

          rightRow++;
        });
      } else if (part.removed) {
        // Highlight removed lines in the left editor
        lines.forEach((line, index) => {
          this.leftEditor.getSession().addMarker(
            new ace.Range(leftRow, 0, leftRow, 1),
            'ace_removed_line',
            'fullLine'
          );

          // Highlight word differences if there are changes within the line
          if (index === 0 && lines.length === 1 && line.trim() !== '') {
            this.highlightWordDifferences(line, '', leftRow, this.leftEditor);
          }

          leftRow++;
        });
      } else {
        // Check for word differences in unchanged lines
        lines.forEach((line) => {
          this.highlightWordDifferences(line, line, leftRow, this.leftEditor);
          this.highlightWordDifferences(line, line, rightRow, this.rightEditor);

          leftRow++;
          rightRow++;
        });
      }
    });
  }

  highlightWordDifferences(leftLine: string, rightLine: string, row: number, editor: ace.Ace.Editor): void {
    const wordDiff = Diff.diffWords(leftLine, rightLine);

    let columnStart = 0;
    wordDiff.forEach((word) => {
      if (word.added || word.removed) {
        const columnEnd = columnStart + word.value.length;

        editor.getSession().addMarker(
          new ace.Range(row, columnStart, row, columnEnd),
          word.added ? 'ace_added_word' : 'ace_removed_word',
          'text'
        );
      }
      columnStart += word.value.length; // Move the cursor forward
    });
  }
}
