#!/usr/bin/env raku

use Samaki;
use Samaki::Exporter::HTML;
use Samaki::Importer::Jupyter;
use Samaki::Page;
use Samaki::Plugins;
use Samaki::Utils;
use Log::Async;
use Terminal::ANSI::OO;
use Terminal::ANSI;
use JSON::Fast;

logger.untapped-ok = True;
logger.send-to("samaki.log") if %*ENV<SAMAKI_DEBUG>;
my %*SUB-MAIN-OPTS = :named-anywhere;
my $editor = %*ENV<EDITOR> // 'vim';

# Mock pane for running cells without UI
class MockPane {
  method put(*@args, *%opts) { }
  method clear() { }
  method lines() { [] }
}

sub edit(IO::Path $path) {
  put t.text-reset;
  shell <<$editor $path>>;
  exit note "no page" unless $path.IO.e;
}

#| Browse pages
multi MAIN(:$dir = $*CWD) {
  my $wkdir = $dir;
  Samaki.new(:wkdir($wkdir.IO), :$editor).start-ui: 'browse';
}

#| Import from another format to a samaki file (default: jupyter)
multi MAIN('import', $target, :$format = 'jupyter') {
  given $format.lc {
    when 'jupyter' {
      my $importer = Samaki::Importer::Jupyter.new;
      my $samaki-name = $importer.import-file($target);
      note "✓ Imported from Jupyter: $samaki-name";
      MAIN($samaki-name);
    }
    default {
      exit note "Unknown import format: $format (supported: jupyter)";
    }
  }
}

#| Make a new page and edit
multi MAIN('new', :$wkdir = $*CWD) {
  my $samaki = Samaki.new(:$wkdir, :$editor);
  my $name = prompt "Please enter a name for the new Samaki page: ";
  my $page = "$name.samaki".IO;
  edit $page;
  $samaki.start-ui: :page($name);
}

#| Edit an existing page
multi MAIN(
  Str $target,     #= filename or directory
  :$wkdir = $*CWD, #= working directory (parent of the data directory)
  Bool :$watch     #= watch for changes and autoreload
) {
  if $target.IO.d && !("{$target}.samaki".IO.e) {
    MAIN(dir => $target);
    return;
  }
  my (:$samaki, :$page, :$page-name) := resolve-target $target, :$wkdir;
  $samaki.start-ui( :$page, :$watch );
}

#| Reset the configuration to the default
multi MAIN('reset-conf') {
  my $wkdir = $*TMPDIR;
  my $q = Samaki.new(:$wkdir, :$editor);
  my $file = $q.config-file;
  if $file.IO.e {
    $file.IO.unlink;
    note "Deleted config file " ~ $file;
  } else {
    note "No config file to delete at " ~ $file;
  }
}

#| Edit the configuration file
multi MAIN('conf') {
  my $wkdir = $*TMPDIR;
  my $q = Samaki.new(:$wkdir, :$editor);
  my $path = $q.config-file;
  $path.IO.e or exit note "No config file at $path";
  shell <<$editor $path>>;
  note "Done editing config file at $path";
}

sub resolve-target($target, :$wkdir!) {
  my $page-path = $target.IO;
  my $page-name;
  my $actual-wkdir;
  if $target.contains('/') {
    $page-name = $page-path.basename.subst(/'.samaki'$/, '');
    $actual-wkdir = $page-path.dirname.IO;
  } else {
    $page-name = $target.subst(/'.samaki'$/, '');
    $actual-wkdir = $wkdir.IO;
  }
   my $samaki = Samaki.new(:wkdir($actual-wkdir), :$editor);
   my $page = Samaki::Page.new(name => $page-name, wkdir => $samaki.wkdir);
   if $page-path.e {
     $page.load(plugins => $samaki.plugins) or
       exit note "Failed to load page: " ~ ($page.errors // "unknown error");
   }
   %( :$samaki, :$page-name, :$page);
}

#| Export a samaki file to another format (default: HTML)
multi MAIN('export', $target, :$wkdir = $*CWD, :$output, :$format = 'html', Bool :$open) {
  my (:$samaki, :$page-name, :$page) := resolve-target $target, :$wkdir;
 
  unless $page.cells.elems {
    note "No cells to export in $page-name.";
    unless $page.filename.IO.e {
      note "Note: The file { $page.filename } does not exist.";
    }
    exit;
  }

  given $format.lc {
    when 'html' {
      my $exporter = Samaki::Exporter::HTML.new(:$page, plugins => $samaki.plugins);
      my $html = $exporter.generate-html();
      my $output-path = $output ?? $output.IO !! $samaki.wkdir.child("$page-name.html");
      spurt $output-path, $html;
      note "Exported to HTML: $output-path";
      shell-open($output-path) if $open;
    }
    default {
      exit note "Unknown export format: $format (supported: html)";
    }
  }
}

#| Run all cells in a samaki file
multi MAIN('run', $target, :$wkdir = $*CWD) {
  my (:$samaki, :$page-name, :$page) := resolve-target $target, :$wkdir;
  disable-output;
  my $*SAMAKI-NO-SHELL-OPEN = True;
  my $mock-pane = MockPane.new;

  my @cells = $page.cells;
  unless @cells {
    note "No cells to run in $page-name.";
    unless $page.filename.IO.e {
      note "Note: The file { $page.filename } does not exist.";
    }
    return;
  }
  note "Running all cells in $page-name.  Cell count: { @cells.elems }";
  for @cells -> $cell {
    print " cell { $cell.name }...";

    try {
      my $action = $cell.select-action // 'run';
      $page.run-cell($cell, btm => $mock-pane, top => $mock-pane, :$action);
      CATCH {
        default {
          say "# Error: $_";
        }
      }
    }

    if $cell.errors {
      say "# Error: { $cell.errors }";
    } else {
      say "ok";
    }
  }

  say "All cells executed";
}
