require "sqlite3"
require "rugged"
require "fileutils"
require_relative "db"

class GitRepo
  attr :path, :error, :db

  def initialize(path, db)
    @path = nil
    @error = nil
    @db = db
    if File.absolute_path?(path)
      if File.exist?(path)
        @path = path
      end
    else
      apath = File.realpath(path)
      if File.exist?(apath)
        @path = apath
      end
    end
  end

  def create_git(project_name, description)
    @error = nil
    ret_val = 0
    File.open("locks/gitcreate", "r") do |f|
      f.flock(File::LOCK_EX)
      fname = File.expand_path("#{project_name}.git", @path)
      if File.exist?(fname)
        @error = "Репозиторий с таким именем уже существует: #{project_name}"
        ret_val = 1
      else
        Dir.mkdir(fname)
        Rugged::Repository.init_at(fname, :bare)
        repo = Rugged::Repository.new(fname)
        created = false
        if repo.bare?
          @error = @db.creategit(project_name, description)
          if @error.nil?
            created = true
          end
        else
          @error = "Репозиторий почему-то не пустой"
        end
        unless created
          FileUtils.rm_rf(fname, secure: true)
        end
      end
    end
    ret_val
  end

  def create_git_db_only(project_name)
    @error = @db.creategit(project_name, "")
    @error
  end

  def getrepos
    repos_data = []
    File.open("locks/gitcreate", "r") do |f|
      f.flock(File::LOCK_SH)
      repos_files = Dir[File.join(@path, "*.git")]
      repos_files.each do |fl|
        repo_name = File.basename(fl, ".git")
        db_info = @db.get_repo_info_by_name(repo_name)
        unless db_info.nil?
          db_info = db_info.first
          repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
        else
          result = create_git_db_only(repo_name)
          if result.nil?
            db_info = @db.get_repo_info_by_name(repo_name)
            db_info = db_info.first
            repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
          end
        end
      end
    end
    repos_data
  end

  def repo_info(reponame, branch = nil)
    info = {}
    result = ""
    @error = nil
    repos_data = { :full => 0 }
    git_path = File.join(@path, reponame + ".git")
    File.open("locks/gitcreate", "r") do |f|
      f.flock(File::LOCK_SH)
      if File.exist?(git_path)
        repo = Rugged::Repository.new(git_path)
        db_info = @db.get_repo_info_by_name(reponame)
        unless db_info.nil?
          db_info = db_info.first
          repos_data = { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :full => 1 }
        else
          result = create_git_db_only(reponame)
          if result.nil?
            db_info = @db.get_repo_info_by_name(reponame)
            db_info = db_info.first
            repos_data = { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :full => 1 }
          end
        end
        if repos_data[:full] == 1
          info[:info] = repos_data
          if repo.empty?
            info[:commits] = []
            info[:branches] = []
            info[:tags] = []
          else
            ref = repo.head
            unless branch.nil?
              ref_name = File.join("refs/heads/", branch)
              ref = repo.references[ref_name]
            end
            commits = []
            unless ref.nil?
              walker = Rugged::Walker.new(repo)
              walker.sorting(Rugged::SORT_DATE)
              walker.push(ref.target)
              commits = walker.map do |commit|
                { :message => commit.message, :author => commit.author, :time => commit.time, :sha => commit.oid }
              end.first(10)
            end
            info[:commits] = commits
            info[:branches] = repo.branches.each_name(:local).sort
            info[:tags] = repo.tags.map { |tag| tag.name }
          end
        else
          @error = result
        end
      else
        @error = "Репозиторий отсутсвует"
      end
    end
    info[:error] = @error
    info
  end
end