# frozen_string_literal: true

# Se encargar de guardar cambios en sitios
# TODO: Implementar rollback en la configuración
SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
  # Crea un sitio, agrega un rol nuevo y guarda los cambios a la
  # configuración en el repositorio git
  def create
    self.site = Site.new params

    add_role temporal: false, rol: 'usuarie'

    I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do
      site.save &&
        site.config.write &&
        commit_config(action: :create)
    end

    add_licencias

    site
  end

  # Actualiza el sitio y guarda los cambios en la configuración
  def update
    I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do
      site.update(params) &&
        site.config.write &&
        commit_config(action: :update)
    end

    change_licencias

    site
  end

  # Genera los Deploy necesarios para el sitio a menos que ya los tenga.
  def build_deploys
    Site::DEPLOYS.map { |deploy| "Deploy#{deploy.to_s.camelcase}" }
                 .each do |deploy|
      next if site.deploys.find_by type: deploy

      site.deploys.build type: deploy
    end
  end

  # Agregar una dirección oculta de Tor al DeployHiddenService y a la
  # configuración del Site.
  def add_onion
    onion  = params[:onion].strip
    deploy = DeployHiddenService.find_by(site: site)

    return false unless !onion.blank? && deploy

    deploy.values[:onion] = onion
    deploy.save

    site.config['onion-location'] = onion
    site.config.write

    commit_config(action: :tor)
  end

  private

  # Guarda los cambios de la configuración en el repositorio git
  def commit_config(action:)
    site.repository
        .commit(usuarie: usuarie,
                file: site.config.path,
                message: I18n.t("site_service.#{action}",
                                name: site.name))
  end

  def add_role(temporal: true, rol: 'invitade')
    site.roles << Rol.new(site: site, usuarie: usuarie,
                          temporal: temporal, rol: rol)
  end

  # Crea la licencia del sitio para cada locale disponible en el sitio
  def add_licencias
    site.locales.each do |locale|
      next unless I18n.available_locales.include? locale

      Mobility.with_locale(locale) do
        add_licencia lang: locale
      end
    end
  end

  def add_licencia(lang:)
    params = ActionController::Parameters.new(
      post: {
        lang: lang,
        title: site.licencia.name,
        description: I18n.t('sites.form.licencia.title'),
        author: %w[Sutty],
        permalink: "#{I18n.t('activerecord.models.licencia').downcase}/",
        content: CommonMarker.render_html(site.licencia.deed)
      }
    )

    PostService.new(site: site, usuarie: usuarie, params: params).create
  end

  # Encuentra la licencia a partir de su enlace permanente y le cambia
  # el contenido
  #
  # TODO: Crear un layout específico para licencias así es más certera
  # la búsqueda.
  def change_licencias
    site.locales.each do |locale|
      Mobility.with_locale(locale) do
        permalink = "#{I18n.t('activerecord.models.licencia').downcase}/"
        post = site.posts(lang: locale).find_by(permalink: permalink)

        post ? change_licencia(post: post) : add_licencia(lang: locale)
      end
    end
  end

  def change_licencia(post:)
    params = ActionController::Parameters.new(
      post: {
        title: site.licencia.name,
        content: CommonMarker.render_html(site.licencia.deed)
      }
    )

    PostService.new(site: site, usuarie: usuarie, post: post,
                    params: params).update
  end
end