
using Godot;

using System.Collections.Generic;
using System;
using Rokojori.Tools;

namespace Rokojori.DocGenerator
{
  [GlobalClass][Tool]
  public partial class CreateDoc : Node
  {
    [Export]
    public string outputPath ="res://.rokojori/cache/docs";

    [Export]
    public bool clearDirectory = false;

    [Export]
    public bool c_sharp = true;

    [Export]
    public bool shaders = true;

    [Export]
    public bool processOnlyNewer = true;

    [Export]
    public int hoursCheckTime = 12;

    [ExportToolButton( "Create")]
    public Callable createButton => Callable.From( ()=>{ Create(); } );

    void Create()
    {  

      var absoluteLibraryPath = ProjectSettings.GlobalizePath( "res://addons/rokojori_action_library/Runtime" );
      var absoluteIconPath    = ProjectSettings.GlobalizePath( "res://addons/rokojori_action_library/Icons" );   
      var absoluteOutputPath  = ProjectSettings.GlobalizePath( outputPath );  

      if ( clearDirectory )
      {
        FilesSync.Delete( absoluteOutputPath );
        FilesSync.EnsureDirectoryExists( absoluteOutputPath );
      }

      var generator = new DocGenerator();
      generator.shaders = shaders;
      generator.cSharp = c_sharp;
      generator.checkChangeTime = processOnlyNewer;

      var icons = Lists.Map( FilesSync.GetFiles( absoluteIconPath, ( fp => fp.fileExtension == ".svg" ) ), fp => fp.fullFileName );
      generator.Generate( absoluteLibraryPath, absoluteOutputPath, icons );
    }


    [Export(PropertyHint.Dir)]
    public string externalDocsPath;

    [ExportToolButton( "Intergrate External")]
    public Callable integrateExternalButton => Callable.From( ()=>{ IntegrateExtarnel(); } );

    void IntegrateExtarnel()
    {  

      var absoluteLibraryPath = ProjectSettings.GlobalizePath( "res://addons/rokojori_action_library/Runtime" );
      var absoluteExternalPath = ProjectSettings.GlobalizePath( externalDocsPath );   

      var libraryFilePath = FilePath.Absolute( absoluteLibraryPath );
      var externalPath = FilePath.Absolute( absoluteExternalPath );  
      
      var externalDocFiles = FilesSync.GetFilesRecursive( absoluteExternalPath, 

        ( fp )=>
        {
          return fp.HasFileExtension( "json" );
        }
        
      );

      var codeFiles = FilesSync.GetFilesRecursive( absoluteLibraryPath, 

        ( fp )=>
        {
          return fp.HasFileExtension( "cs" );
        }
        
      );

      var namesMap = codeFiles.ToMap( cf => cf.fullFileName );

      var missing = new List<FilePath>();
      var mapped = new Dictionary<FilePath,FilePath>();
      var found = new List<FilePath>();
      var csToDocs = new Dictionary<FilePath,FilePath>();

      externalDocFiles.ForEach(
        ( docFile )=>
        {
          var relativeFilePath = externalPath.MakeRelative( docFile );
          var relativePath = docFile.path.ReplaceEnd( ".json" );

          var libPath = libraryFilePath.MakeRelative( relativePath );

          if ( ! libPath.Exists() )
          {
            var name = libPath.fullFileName;

            if ( namesMap.ContainsKey( name ) )
            {
              // this.LogInfo( "Remapping:", relativePath, "using:", namesMap[ name ].path );
              mapped[ docFile ] = namesMap[ name ]; 
            }
            else
            {   
              this.LogInfo( "Could not find:", relativePath );
              missing.Add( docFile );
            }
            
          }
          else
          {
            found.Add( libPath );
            csToDocs[ libPath ] = docFile;
          }
        }
      );

      // if ( missing.Count == 0 )
      // {
      //   this.LogInfo( "All good" );
      //   return;
      // }

    
      if ( found.Count == 0 )
      {
        return;
      }

      var editor = new ClassDocEditor();
      var source = found[ 0 ].LoadUTF8();
      editor.originalTokens = LexerList.Create( CSharpLexer.Lex( source ), LexerMatcherLibrary.Ignore );
      var objects = CSharpLexer.GetAllObjectDefinitions( editor.originalTokens.events );
      var classObject = objects.Find( obj => obj.type.Is( LexerMatcherLibrary.ClassMatcher ) );
      editor.source = source;

      var doc = csToDocs[ found[ 0 ] ].LoadJSON<OnlineDocJSON>();
      editor.Process( classObject, doc );

      // this.LogInfo( editing );
    }
  }
}