module Makit
  class DotNet
    def self.is_installed?
      File.exist?(Makit::Environment.which("dotnet"))
    end

    def self.version
      `dotnet --version`
    end

    def self.project_short_name(project_path)
      project_name = File.basename(project_path, ".csproj")
      project_name
    end

    def self.new_project(template, name, output, args = "")
      if Dir.exist? output
        puts "  .csproj ".colorize(:grey) + "#{name}".colorize(:green)
      else
        "dotnet new #{template} --name #{name} --output #{output} #{args}".run
      end
    end

    def self.set_project_target_framework(project_hint, target_framework)
      project_path = find_project(project_hint)
      project_content = File.read(project_path)
      project_content.gsub!(/<TargetFramework>.*<\/TargetFramework>/, "<TargetFramework>#{target_framework}</TargetFramework>")
      File.write(project_path, project_content)
    end

    def self.find_project(project_hint)
      matches = []
      Dir.glob("**/*.csproj").each do |project_path|
        #project_name = File.basename(project_path, ".csproj")
        if project_path.include?(project_hint)
          matches << project_path
        end
      end
      if matches.length == 1
        return matches.first
      elsif matches.length > 1
        raise "Multiple projects found matching #{project_hint}".colorize(:red)
      end
      raise "No project found matching #{project_hint}".colorize(:red)
    end

    def self.add_package(project_path, package_name)
      if (!File.exist?(project_path))
        actual_project_path = Makit::DotNet::find_project(project_path)
        if (!File.exist?(actual_project_path))
          raise "Project #{project_path} does not exist".colorize(:red)
        else
          project_path = actual_project_path
        end
      end
      project_content = File.read(project_path)
      if (!project_content.include?("\"#{package_name}\""))
        "dotnet add #{project_path} package #{package_name}".run
      else
        puts "  package ".colorize(:grey) + "#{package_name}".colorize(:green)
        #puts "  #{project_short_name(project_path)} has package #{package_name}".colorize(:grey)
      end
    end

    def self.add_packages(project_path, packages)
      packages.each do |package|
        add_package(project_path, package)
      end
    end

    def self.add_reference(project_path, reference_path)
      if (!File.exist?(project_path))
        actual_project_path = Makit::DotNet::find_project(project_path)
        if (!File.exist?(actual_project_path))
          raise "Project #{project_path} does not exist".colorize(:red)
        else
          project_path = actual_project_path
        end
      end
      if (!File.exist?(reference_path))
        actual_reference_path = Makit::DotNet::find_project(reference_path)
        if (!File.exist?(actual_reference_path))
          raise "Project #{reference_path} does not exist".colorize(:red)
        else
          reference_path = actual_reference_path
        end
      end
      project_content = File.read(project_path)
      if (project_content.include?(File.basename(reference_path)))
        puts "  reference ".colorize(:grey) + "#{reference_path}".colorize(:green)
        #puts "  #{project_short_name(project_path)} references #{project_short_name(reference_path)}".colorize(:grey)
        #puts "  reference ".colorize(:grey) + "#{reference_path}".colorize(:yellow) + " is in ".colorize(:grey) + "#{project_path}".colorize(:yellow)
      else
        "dotnet add #{project_path} reference #{reference_path}".run
      end
    end

    def self.add_references(project_path, references)
      references.each do |reference|
        add_reference(project_path, reference)
      end
    end

    def self.new_solution(name)
      if File.exist? "#{name}.sln"
        #puts "Solution #{name}.sln already exists".colorize(:yellow)
        #puts "  #{name}.sln".colorize(:green) + " exists".colorize(:grey)
      else
        "dotnet new sln --name #{name}".run
      end
    end

    def self.build(project_path, configuration = "Release", output = "artifacts")
      project_dir = File.dirname(project_path)
      newest_file = Makit::Directory::get_newest_file(project_dir)
      command_request = Makit::RUNNER::parse_command_request("dotnet build #{project_path} --configuration #{configuration} --output #{output}")
      if newest_file.nil?
        newest_file_date = Time.now
        RUNNER.cache_run(command_request, newest_file_date)
      else
        newest_file_date = File.mtime(newest_file)
        RUNNER.cache_run(command_request, newest_file_date)
      end
    end

    def self.publish(project_path, configuration = "Release", output = "artifacts")
      project_dir = File.dirname(project_path)
      newest_file = Makit::Directory::get_newest_file(project_dir)
      command_request = Makit::RUNNER::parse_command_request("dotnet publish #{project_path} --configuration #{configuration} --output #{output}")
      if newest_file.nil?
        newest_file_date = Time.now
        RUNNER.cache_run(command_request, newest_file_date)
      else
        newest_file_date = File.mtime(newest_file)
        RUNNER.cache_run(command_request, newest_file_date)
      end
    end

    def self.test(project_path, configuration = "Release", output = "artifacts")
      project_dir = File.dirname(project_path)
      newest_file = Makit::Directory::get_newest_file(project_dir)
      command_request = Makit::RUNNER::parse_command_request("dotnet test #{project_path} --configuration #{configuration} --output #{output}")
      if newest_file.nil?
        newest_file_date = Time.now
        RUNNER.cache_run(command_request, newest_file_date)
      else
        newest_file_date = File.mtime(newest_file)
        RUNNER.cache_run(command_request, newest_file_date)
      end
    end

    def self.sln_add_projects(sln_name)
      if !File.exist? "#{sln_name}.sln"
        raise "Solution #{sln_name}.sln does not exist"
      else
        sln_path = "#{sln_name}.sln"
        sln_content = File.read(sln_path)
        Dir.glob("**/*.csproj").each do |project_path|
          project_name = File.basename(project_path, ".csproj")
          if (sln_content.include?("\"#{project_name}\""))
            #puts "  #{project_name}".colorize(:green) + " is in ".colorize(:grey) + "#{sln_path}".colorize(:green)
            #puts "Project #{project_name} already exists in #{sln_path}".colorize(:yellow)
          else
            "dotnet sln #{sln_path} add #{project_path}".run
          end
        end
      end
    end

    def self.format_project(project_path)
      project_name = File.basename(project_path, ".csproj")
      "dotnet tool update --global dotnet-format".run
      "dotnet format #{project_path}".run
    end

    def self.upgrade_project(project_path)
      project_name = File.basename(project_path, ".csproj")
      "dotnet tool install --global dotnet-outdated-tool".run
      "dotnet outdated #{project_path} --upgrade:Auto".run
    end
  end # class DotNet
end # module Makit