#!/usr/bin/env ruby
require 'net/http'
require 'json'
require 'uri'
require 'yaml'
require 'optparse'

# Configuration mapping
ENV_CONFIG = {
  'stg' => {
    url: "https://git.staging.jamkazam.com/api/v1",
    token_var: "GITEA_TOKEN_STG"
  },
  'prd' => {
    url: "https://git.jamkazam.com/api/v1",
    token_var: "GITEA_TOKEN_PRD"
  }
}

options = { env: 'stg' }
OptionParser.new do |opts|
  opts.banner = "Usage: ruby sync-gitea-repos.rb [options] <bitbucket_user> <bitbucket_pass>"
  opts.on("-e", "--env ENV", "Environment (stg or prd, default stg)") { |v| options[:env] = v }
end.parse!

if ARGV.length < 2
  puts "❌ Error: Missing Bitbucket credentials."
  puts "Usage: ruby sync-gitea-repos.rb --env [stg|prd] <bb_user> <bb_pass>"
  exit 1
end

BB_USER = ARGV[0]
BB_PASS = ARGV[1]

# Select config
config = ENV_CONFIG[options[:env]]
if config.nil?
  puts "❌ Error: Invalid environment '#{options[:env]}'. Use 'stg' or 'prd'."
  exit 1
end

# Resolve Token
GITEA_TOKEN = ENV[config[:token_var]] || ENV['GITEA_TOKEN']
GITEA_URL = config[:url]
GITEA_OWNER = "seth"
MANIFEST_FILE = File.expand_path('gitea-repos.yaml', __dir__)

if GITEA_TOKEN.nil? || GITEA_TOKEN.empty?
  puts "❌ Error: API Token environment variable '#{config[:token_var]}' is not set."
  exit 1
end

def gitea_request(method, path, payload = nil)
  uri = URI.parse("#{GITEA_URL}#{path}")
  header = {
    'Content-Type' => 'application/json',
    'Authorization' => "token #{GITEA_TOKEN}"
  }
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.read_timeout = 300

  case method
  when :get then req = Net::HTTP::Get.new(uri.request_uri, header)
  when :post then req = Net::HTTP::Post.new(uri.request_uri, header); req.body = payload.to_json if payload
  when :delete then req = Net::HTTP::Delete.new(uri.request_uri, header)
  end
  http.request(req)
end

puts "🚀 Reconciling Gitea mirrors for #{options[:env].upcase}..."
puts "🔗 API: #{GITEA_URL}"

# 1. Load Manifest
manifest = YAML.load_file(MANIFEST_FILE)
desired_repos = manifest['repositories']
desired_names = desired_repos.map { |r| r['name'] }

# 2. Get Current State from Gitea
puts "🔍 Fetching current repositories..."
resp = gitea_request(:get, "/users/#{GITEA_OWNER}/repos")
if resp.code != "200"
  puts "❌ Failed to fetch repos: #{resp.code} #{resp.body}"
  exit 1
end
current_repos = JSON.parse(resp.body)
current_names = current_repos.map { |r| r['name'] }

# 3. Reconcile: Delete repos not in manifest
repos_to_delete = current_names - desired_names
repos_to_delete.each do |name|
  puts "🗑️  Deleting repository '#{name}' (not in manifest)..."
  gitea_request(:delete, "/repos/#{GITEA_OWNER}/#{name}")
end

# 4. Reconcile: Create/Update mirrors
desired_repos.each do |repo|
  name = repo['name']
  url = repo['url']

  if current_names.include?(name)
    repo_info = current_repos.find { |r| r['name'] == name }
    if repo_info['empty']
      puts "⚠️  Mirror '#{name}' exists but is EMPTY. Recreating..."
      gitea_request(:delete, "/repos/#{GITEA_OWNER}/#{name}")
    else
      puts "✅ Mirror '#{name}' already exists. Skipping."
      next
    end
  end

  puts "🚀 Creating mirror for '#{name}'..."
  payload = {
    "clone_addr" => url,
    "auth_username" => BB_USER,
    "auth_password" => BB_PASS,
    "repo_name" => name,
    "mirror" => true,
    "mirror_interval" => "10m",
    "service" => "bitbucket",
    "repo_owner" => GITEA_OWNER,
    "lfs" => true,
    "releases" => true
  }
  
  res = gitea_request(:post, "/repos/migrate", payload)
  if res.code == "201"
    puts "✨ Successfully created mirror for '#{name}'."
  else
    puts "❌ Failed to create mirror for '#{name}': #{res.code} #{res.body}"
  end
end

puts "\n🎯 Reconcile complete for #{options[:env].upcase}."
