require "kramdown"
require "yaml"
require "pressa/utils/file_writer"
require "pressa/site"
require "pressa/views/layout"
require "pressa/views/icons"

module Pressa
  module Utils
    class MarkdownRenderer
      EXCERPT_LENGTH = 300

      def can_render_file?(filename:, extension:)
        extension == "md"
      end

      def render(site:, file_path:, target_dir:)
        content = File.read(file_path)
        metadata, body_markdown = parse_content(content)

        html_body = render_markdown(body_markdown)

        page_title = presence(metadata["Title"]) || File.basename(file_path, ".md").capitalize
        page_type = presence(metadata["Page type"]) || "website"
        page_description = presence(metadata["Description"]) || generate_excerpt(body_markdown)
        show_extension = ["true", "yes", true].include?(metadata["Show extension"])

        slug = File.basename(file_path, ".md")

        relative_dir = File.dirname(file_path).sub(/^.*?\/public\/?/, "")
        relative_dir = "" if relative_dir == "."

        canonical_path = if show_extension
          "/#{relative_dir}/#{slug}.html".squeeze("/")
        else
          "/#{relative_dir}/#{slug}/".squeeze("/")
        end

        html = render_layout(
          site:,
          page_subtitle: page_title,
          canonical_url: site.url_for(canonical_path),
          body: html_body,
          page_description:,
          page_type:
        )

        output_filename = if show_extension
          "#{slug}.html"
        else
          File.join(slug, "index.html")
        end

        output_path = File.join(target_dir, output_filename)
        FileWriter.write(path: output_path, content: html)
      end

      private

      def parse_content(content)
        if content =~ /\A---\s*\n(.*?)\n---\s*\n(.*)/m
          yaml_content = $1
          markdown = $2
          metadata = YAML.safe_load(yaml_content) || {}
          [metadata, markdown]
        else
          [{}, content]
        end
      end

      def render_markdown(markdown)
        Kramdown::Document.new(
          markdown,
          input: "GFM",
          hard_wrap: false,
          syntax_highlighter: "rouge",
          syntax_highlighter_opts: {
            line_numbers: false,
            wrap: true
          }
        ).to_html
      end

      def render_layout(site:, page_subtitle:, canonical_url:, body:, page_description:, page_type:)
        layout = Views::Layout.new(
          site:,
          page_subtitle:,
          canonical_url:,
          page_description:,
          page_type:,
          content: PageView.new(page_title: page_subtitle, body:)
        )

        layout.call
      end

      class PageView < Phlex::HTML
        def initialize(page_title:, body:)
          @page_title = page_title
          @body = body
        end

        def view_template
          article(class: "container") do
            h1 { @page_title }
            raw(safe(@body))
          end

          div(class: "row clearfix") do
            p(class: "fin") do
              raw(safe(Views::Icons.code))
            end
          end
        end
      end

      def generate_excerpt(markdown)
        text = markdown.dup

        # Drop inline and reference-style images before links are simplified.
        text.gsub!(/!\[[^\]]*\]\([^)]+\)/, "")
        text.gsub!(/!\[[^\]]*\]\[[^\]]+\]/, "")

        # Replace inline and reference links with just their text.
        text.gsub!(/\[([^\]]+)\]\([^)]+\)/, '\1')
        text.gsub!(/\[([^\]]+)\]\[[^\]]+\]/, '\1')

        # Remove link reference definitions such as: [foo]: http://example.com
        text.gsub!(/(?m)^\[[^\]]+\]:\s*\S.*$/, "")

        text.gsub!(/<[^>]+>/, "")
        text.gsub!(/\s+/, " ")
        text.strip!

        return nil if text.empty?

        "#{text[0...EXCERPT_LENGTH]}..."
      end

      def presence(value)
        return value unless value.respond_to?(:strip)

        stripped = value.strip
        stripped.empty? ? nil : stripped
      end
    end
  end
end
