# frozen_string_literal: true

module SeedData
  class Categories
    def self.with_default_locale
      SeedData::Categories.new(SiteSetting.default_locale)
    end

    def initialize(locale)
      @locale = locale
    end

    def create(site_setting_names: nil)
      I18n.with_locale(@locale) do
        categories(site_setting_names).each { |params| create_category(**params) }
      end
    end

    def update(site_setting_names: nil, skip_changed: false)
      I18n.with_locale(@locale) do
        categories(site_setting_names).each do |params|
          params.slice!(:site_setting_name, :name, :description)
          params[:skip_changed] = skip_changed
          update_category(**params)
        end
      end
    end

    def reseed_options
      I18n.with_locale(@locale) do
        categories
          .map do |params|
            category = find_category(params[:site_setting_name])
            next unless category

            { id: params[:site_setting_name], name: category.name, selected: unchanged?(category) }
          end
          .compact
      end
    end

    private

    def categories(site_setting_names = nil)
      categories = [
        {
          site_setting_name: "uncategorized_category_id",
          name: I18n.t("uncategorized_category_name"),
          description: nil,
          position: 0,
          color: "0088CC",
          text_color: "FFFFFF",
          permissions: {
            everyone: :full,
          },
          force_permissions: true,
          force_existence: true,
        },
        {
          site_setting_name: "meta_category_id",
          name: I18n.t("meta_category_name"),
          description: I18n.t("meta_category_description"),
          position: 1,
          color: "808281",
          text_color: "FFFFFF",
          permissions: {
            everyone: :full,
          },
          force_permissions: true,
          sidebar: true,
        },
        {
          site_setting_name: "staff_category_id",
          name: I18n.t("staff_category_name"),
          description: I18n.t("staff_category_description"),
          position: 2,
          color: "E45735",
          text_color: "FFFFFF",
          permissions: {
            staff: :full,
          },
          force_permissions: true,
          sidebar: true,
        },
        {
          site_setting_name: "general_category_id",
          name: I18n.t("general_category_name"),
          description: I18n.t("general_category_description"),
          position: 3,
          color: "25AAE2",
          text_color: "FFFFFF",
          permissions: {
            everyone: :full,
          },
          force_permissions: true,
          sidebar: true,
          default_composer_category: true,
        },
      ]

      if site_setting_names
        categories.select! { |c| site_setting_names.include?(c[:site_setting_name]) }
      end

      categories
    end

    def create_category(
      site_setting_name:,
      name:,
      description:,
      position:,
      color:,
      text_color:,
      permissions:,
      force_permissions:,
      force_existence: false,
      sidebar: false,
      default_composer_category: false
    )
      category_id = SiteSetting.get(site_setting_name)

      if should_create_category?(category_id, force_existence)
        category =
          Category.new(
            name: unused_category_name(category_id, name),
            description: description,
            user_id: Discourse::SYSTEM_USER_ID,
            position: position,
            color: color,
            text_color: text_color,
          )

        category.skip_category_definition = true if description.blank?
        category.set_permissions(permissions)
        category.save!

        SiteSetting.set(site_setting_name, category.id)

        if sidebar
          sidebar_categories = SiteSetting.default_sidebar_categories.split("|")
          sidebar_categories << category.id
          SiteSetting.set("default_sidebar_categories", sidebar_categories.join("|"))
        end

        SiteSetting.set("default_composer_category", category.id) if default_composer_category
      elsif category = Category.find_by(id: category_id)
        if description.present? && (category.topic_id.blank? || !Topic.exists?(category.topic_id))
          category.description = description
          category.create_category_definition
        end

        if force_permissions
          category.set_permissions(permissions)
          category.save!(validate: false) if category.changed?
        end
      end
    end

    def should_create_category?(category_id, force_existence)
      return false if User.human_users.any?

      if category_id > 0
        force_existence ? !Category.exists?(category_id) : false
      else
        true
      end
    end

    def unused_category_name(category_id, name)
      category_exists =
        Category.where(
          "id <> :id AND LOWER(name) = :name",
          id: category_id,
          name: name.downcase,
        ).exists?

      category_exists ? "#{name}#{SecureRandom.hex}" : name
    end

    def update_category(site_setting_name:, name:, description:, skip_changed:)
      category = find_category(site_setting_name)
      return if !category || (skip_changed && !unchanged?(category))

      name = unused_category_name(category.id, name)
      category.name = name
      category.slug = Slug.for(name, "")
      category.save!

      if description.present? && description_post = category&.topic&.first_post
        changes = { title: I18n.t("category.topic_prefix", category: name), raw: description }
        description_post.revise(Discourse.system_user, changes, skip_validations: true)
      end
    end

    def find_category(site_setting_name)
      category_id = SiteSetting.get(site_setting_name)
      Category.find_by(id: category_id) if category_id > 0
    end

    def unchanged?(category)
      if description_post = category&.topic&.first_post
        return description_post.last_editor_id == Discourse::SYSTEM_USER_ID
      end

      true
    end
  end
end