# frozen_string_literal: true

require_dependency 'global_path'

module Stylesheet
  class Importer
    include GlobalPath

    THEME_TARGETS ||= %w{embedded_theme mobile_theme desktop_theme}

    def self.plugin_assets
      @plugin_assets ||= {}
    end

    def self.register_imports!
      Discourse.plugins.each do |plugin|
        plugin_directory_name = plugin.directory_name

        ["", "mobile", "desktop"].each do |type|
          asset_name = type.present? ? "#{plugin_directory_name}_#{type}" : plugin_directory_name
          stylesheets = type.present? ? DiscoursePluginRegistry.send("#{type}_stylesheets") : DiscoursePluginRegistry.stylesheets

          plugin_assets[asset_name] = stylesheets[plugin_directory_name] if plugin_directory_name.present?
        end
      end

    end

    register_imports!

    def font
      body_font = DiscourseFonts.fonts.find { |f| f[:key] == SiteSetting.base_font }
      heading_font = DiscourseFonts.fonts.find { |f| f[:key] == SiteSetting.heading_font }
      contents = +""

      if body_font.present?
        contents << <<~EOF
          #{font_css(body_font)}

          :root {
            --font-family: #{body_font[:stack]};
          }
        EOF
      end

      if heading_font.present?
        contents << <<~EOF
          #{font_css(heading_font)}

          :root {
            --heading-font-family: #{heading_font[:stack]};
          }
        EOF
      end

      contents
    end

    def wizard_fonts
      contents = +""

      DiscourseFonts.fonts.each do |font|
        if font[:key] == "system"
          # Overwrite font definition because the preview canvases in the wizard require explicit @font-face definitions.
          # uses same technique as https://github.com/jonathantneal/system-font-css
          font[:variants] = [
            { src: 'local(".SFNS-Regular"), local(".SFNSText-Regular"), local(".HelveticaNeueDeskInterface-Regular"), local(".LucidaGrandeUI"), local("Segoe UI"), local("Ubuntu"), local("Roboto-Regular"), local("DroidSans"), local("Tahoma")', weight: 400 },
            { src: 'local(".SFNS-Bold"), local(".SFNSText-Bold"), local(".HelveticaNeueDeskInterface-Bold"), local(".LucidaGrandeUI"), local("Segoe UI Bold"), local("Ubuntu Bold"), local("Roboto-Bold"), local("DroidSans-Bold"), local("Tahoma Bold")', weight: 700 }
          ]
        end

        contents << font_css(font)
        contents << <<~EOF
          .body-font-#{font[:key].tr("_", "-")} {
            font-family: #{font[:stack]};
          }
          .heading-font-#{font[:key].tr("_", "-")} h2 {
            font-family: #{font[:stack]};
          }
        EOF
      end

      contents
    end

    def category_backgrounds
      contents = +""
      Category.where('uploaded_background_id IS NOT NULL').each do |c|
        contents << category_css(c) if c.uploaded_background&.url.present?
      end

      contents
    end

    def import_color_definitions
      contents = +""
      DiscoursePluginRegistry.color_definition_stylesheets.each do |name, path|
        contents << "\n\n// Color definitions from #{name}\n\n"
        contents << File.read(path.to_s)
        contents << "\n\n"
      end

      theme_id = @theme_id || SiteSetting.default_theme_id
      resolved_ids = Theme.transform_ids([theme_id])

      if resolved_ids
        theme = Theme.find_by_id(theme_id)
        contents << theme&.scss_variables.to_s
        Theme.list_baked_fields(resolved_ids, :common, :color_definitions).each do |field|
          contents << "\n\n// Color definitions from #{field.theme.name}\n\n"

          if field.theme_id == theme.id
            contents << field.value
          else
            contents << field.compiled_css(prepended_scss)
          end
          contents << "\n\n"
        end
      end
      contents
    end

    def import_wcag_overrides
      if @color_scheme_id && ColorScheme.find_by_id(@color_scheme_id)&.is_wcag?
        return "@import \"wcag\";"
      end
      ""
    end

    def color_variables
      contents = +""
      if @color_scheme_id
        colors = begin
          ColorScheme.find(@color_scheme_id).resolved_colors
        rescue
          ColorScheme.base_colors
        end
      elsif (@theme_id && !theme.component)
        colors = theme&.color_scheme&.resolved_colors || ColorScheme.base_colors
      else
        # this is a slightly ugly backwards compatibility fix,
        # we shouldn't be using the default theme color scheme for components
        # (most components use CSS custom properties which work fine without this)
        colors = Theme.find_by_id(SiteSetting.default_theme_id)&.color_scheme&.resolved_colors ||
          ColorScheme.base_colors
      end

      colors.each do |n, hex|
        contents << "$#{n}: ##{hex} !default; "
      end

      contents
    end

    def public_image_path
      image_path = UrlHelper.absolute("#{Discourse.base_path}/images")
      "$public_image_path: \"#{image_path}\"; "
    end

    def prepended_scss
      "#{color_variables} #{public_image_path} @import \"common/foundation/variables\"; @import \"common/foundation/mixins\"; "
    end

    def initialize(options)
      @theme = options[:theme]
      @theme_id = options[:theme_id]
      @color_scheme_id = options[:color_scheme_id]

      if @theme && !@theme_id
        # make up an id so other stuff does not bail out
        @theme_id = @theme.id || -1
      end
    end

    def theme_import(target)
      attr = target == :embedded_theme ? :embedded_scss : :scss
      target = target.to_s.gsub("_theme", "").to_sym

      contents = +""

      fields = theme.list_baked_fields(target, attr)
      fields.map do |field|
        value = field.value
        if value.present?
          contents << <<~COMMENT
          // Theme: #{field.theme.name}
          // Target: #{field.target_name} #{field.name}
          // Last Edited: #{field.updated_at}
          COMMENT

          contents << value
        end

      end
      contents
    end

    def theme
      unless @theme
        @theme = (@theme_id && Theme.find(@theme_id)) || :nil
      end
      @theme == :nil ? nil : @theme
    end

    def category_css(category)
      full_slug = category.full_slug.split("-")[0..-2].join("-")
      "body.category-#{full_slug} { background-image: url(#{upload_cdn_path(category.uploaded_background.url)}) }\n"
    end

    def font_css(font)
      contents = +""

      if font[:variants].present?
        font[:variants].each do |variant|
          src = variant[:src] ? variant[:src] : "asset-url(\"/fonts/#{variant[:filename]}?v=#{DiscourseFonts::VERSION}\") format(\"#{variant[:format]}\")"
          contents << <<~EOF
            @font-face {
              font-family: #{font[:name]};
              src: #{src};
              font-weight: #{variant[:weight]};
            }
          EOF
        end
      end

      contents
    end

  end
end
