#!/usr/bin/env ruby

environment = ENV.fetch("RACK_ENV", "development")
require "dotenv/load" if environment == "development"

abort "Environnement non pris en charge." unless
  %w[development production].include?(
    ENV.fetch("RACK_ENV", "development")
  )

require "date"
require "io/console"

require_relative "../lib/database"

console = IO.console or abort "Terminal interactif requis."

if environment == "production" &&
    DB[:members].where(core_member: true).count.positive?
  abort "Un Noyau existe déjà."
end

verified_status_id = DB[:account_statuses]
  .where(name: "Verified")
  .get(:id)

abort "Statut Verified introuvable." unless verified_status_id

find_member = lambda do |email|
  account = DB[:accounts]
    .where(Sequel.function(:lower, :email) => email)
    .first

  abort "Compte introuvable : #{email}" unless account

  abort "Adresse électronique non vérifiée : #{email}" unless
    account[:status_id] == verified_status_id

  member = DB[:members]
    .where(account_id: account[:id])
    .first

  abort "Fiche membre introuvable : #{email}" unless member

  abort "Une personne physique est requise : #{email}" unless
    member[:kind] == "individual"

  member
end

console.print "Date de l'assemblée (AAAA-MM-JJ) : "
date_input = console.gets&.strip

unless date_input&.match?(/\A\d{4}-\d{2}-\d{2}\z/)
  abort "Format attendu : AAAA-MM-JJ."
end

begin
  assembly_date = Date.iso8601(date_input)
rescue Date::Error
  abort "Date invalide."
end

abort "La date ne peut pas être dans le futur." if
  assembly_date > Date.today

assembly_datetime = Time.utc(
  assembly_date.year,
  assembly_date.month,
  assembly_date.day
)

console.puts
console.puts "Saisissez les adresses électroniques des membres désignés."
console.puts "Une adresse par ligne. Entrée pour terminer."
console.puts

emails = []

loop do
  console.print "Adresse électronique : "
  email = console.gets&.strip&.downcase

  break if email.to_s.empty?

  abort "Adresse déjà saisie : #{email}" if emails.include?(email)

  emails << email
end

minimum_members = environment == "production" ? 3 : 1

abort "Au moins #{minimum_members} membre(s) sont nécessaires." if
  emails.length < minimum_members

members = emails.map do |email|
  [email, find_member.call(email)]
end

console.puts
console.print "Adresse de la personne qui enregistre la décision : "
recorded_by_email = console.gets&.strip&.downcase

abort "Adresse électronique obligatoire." if
  recorded_by_email.to_s.empty?

recorded_by = find_member.call(recorded_by_email)

console.puts
console.puts "Environnement : #{environment}"
console.puts "Date de l'assemblée : #{assembly_date}"
console.puts
console.puts "Membres du Noyau :"

members.each do |email, member|
  name = "#{member[:first_name]} #{member[:last_name]}"
  console.puts "  #{name} (#{email})"
end

console.puts
console.puts "Décision enregistrée par : #{recorded_by_email}"
console.puts
console.print "Confirmer l'initialisation ? [o/N] "

abort "Opération annulée." unless %w[o oui].include?(
  console.gets&.strip&.downcase
)

if environment == "production" &&
    DB[:members].where(core_member: true).count.positive?
  abort "Un Noyau existe déjà."
end

DB.transaction do
  members.each do |_email, member|
    membership = DB[:memberships]
      .where(
        member_id: member[:id],
        status: %w[pending accepted],
        ended_at: nil
      )
      .first

    if membership && membership[:status] == "pending"
      DB[:memberships]
        .where(id: membership[:id])
        .update(
          status: "accepted",
          decided_at: assembly_datetime,
          recorded_by: recorded_by[:id]
        )
    elsif membership.nil?
      DB[:memberships].insert(
        member_id: member[:id],
        status: "accepted",
        requested_at: assembly_datetime,
        decided_at: assembly_datetime,
        recorded_by: recorded_by[:id]
      )
    end

    DB[:members]
      .where(id: member[:id])
      .update(core_member: true)
  end
end

puts "Noyau initialisé (#{members.length} membres)."

