module fortplot_pdf_axes_text
    !! PDF axis text rendering module
    !!
    !! Handles title, axis labels, and mixed-font text rendering with mathtext support.

    use iso_fortran_env, only: wp => real64
    use fortplot_pdf_core, only: pdf_context_core, PDF_LABEL_SIZE, PDF_TITLE_SIZE
    use fortplot_constants, only: XLABEL_VERTICAL_OFFSET
    use fortplot_pdf_text, only: draw_pdf_text, draw_pdf_text_bold, &
                                 draw_mixed_font_text, draw_rotated_mixed_font_text, &
                                 draw_pdf_mathtext, estimate_pdf_text_width
    use fortplot_text_helpers, only: prepare_mathtext_if_needed
    use fortplot_text_layout, only: has_mathtext, preprocess_math_text
    use fortplot_latex_parser, only: process_latex_in_text
    use fortplot_mathtext, only: mathtext_element_t, parse_mathtext
    use fortplot_pdf_mathtext_render, only: render_mathtext_element_pdf
    use fortplot_unicode, only: utf8_char_length, utf8_to_codepoint
    implicit none
    private

    ! Public procedures
    public :: draw_pdf_title_and_labels
    public :: render_mixed_text
    public :: render_rotated_mixed_text

contains

    subroutine draw_pdf_title_and_labels(ctx, title, xlabel, ylabel, &
                                         plot_area_left, plot_area_bottom, &
                                         plot_area_width, plot_area_height, &
                                         y_tick_label_max_width)
        !! Draw plot title and axis labels
        type(pdf_context_core), intent(inout) :: ctx
        character(len=*), intent(in), optional :: title, xlabel, ylabel
        real(wp), intent(in) :: plot_area_left, plot_area_bottom, plot_area_width, &
                                plot_area_height
        real(wp), intent(in), optional :: y_tick_label_max_width

        real(wp) :: title_x, title_y
        real(wp) :: xlabel_x, xlabel_y
        real(wp) :: ylabel_x, ylabel_y
        real(wp) :: width_pt
        real(wp) :: y_tick_w
        character(len=512) :: processed_title, processed_xlabel, processed_ylabel
        integer :: processed_len
        real(wp), parameter :: TITLE_GAP = 6.0_wp
        real(wp), parameter :: Y_TICK_GAP_LOCAL = 1.0_wp
        real(wp), parameter :: YLABEL_PAD = 1.0_wp
        real(wp), parameter :: LABEL_THICKNESS = 1.2_wp*PDF_LABEL_SIZE

        ! Draw title (centered at top)
        if (present(title)) then
            if (len_trim(title) > 0) then
                ! Process LaTeX commands for accurate width calculation
                call process_latex_in_text(trim(title), processed_title, processed_len)

                width_pt = estimate_pdf_text_width(processed_title(1:processed_len), &
                                                   PDF_TITLE_SIZE)
                title_x = plot_area_left + 0.5_wp*plot_area_width - 0.5_wp*width_pt
                title_y = plot_area_bottom + plot_area_height + TITLE_GAP
                ! Process LaTeX commands to Unicode and render with mixed fonts
                ! Use mathtext rendering for title to handle superscripts properly
                call draw_pdf_mathtext(ctx, title_x, title_y, trim(title), &
                                       PDF_TITLE_SIZE)
            end if
        end if

        ! Draw X-axis label (centered at bottom).
        if (present(xlabel)) then
            if (len_trim(xlabel) > 0) then
                ! Process LaTeX commands for accurate width calculation
                call process_latex_in_text(trim(xlabel), processed_xlabel, &
                                           processed_len)

                width_pt = estimate_pdf_text_width(processed_xlabel(1:processed_len), &
                                                   PDF_LABEL_SIZE)
                xlabel_x = plot_area_left + 0.5_wp*plot_area_width - 0.5_wp*width_pt
                xlabel_y = plot_area_bottom - real(XLABEL_VERTICAL_OFFSET, wp)
                call render_mixed_text(ctx, xlabel_x, xlabel_y, trim(xlabel))
            end if
        end if

        ! Draw Y-axis label (rotated on left) - anchor point is the right edge of the
        ! rotated glyphs (text extends to the left in device X).
        if (present(ylabel)) then
            if (len_trim(ylabel) > 0) then
                ! Process LaTeX commands for accurate width calculation
                call process_latex_in_text(trim(ylabel), processed_ylabel, &
                                           processed_len)

                y_tick_w = 0.0_wp
                if (present(y_tick_label_max_width)) y_tick_w = y_tick_label_max_width

                ! Place y-label block left of the y-tick label block by a fixed padding.
                ! Account for rotated text matrix: glyphs extend left of (ylabel_x).
                ylabel_x = plot_area_left - Y_TICK_GAP_LOCAL - y_tick_w - YLABEL_PAD

                ! Vertically center rotated label: its extent along Y equals the
                ! unrotated text width in points.
                width_pt = estimate_pdf_text_width(processed_ylabel(1:processed_len), &
                                                   PDF_LABEL_SIZE)
                ylabel_y = plot_area_bottom + 0.5_wp*plot_area_height - 0.5_wp*width_pt
                call render_rotated_mixed_text(ctx, ylabel_x, ylabel_y, trim(ylabel))
            end if
        end if
    end subroutine draw_pdf_title_and_labels

    subroutine render_mixed_text(ctx, x, y, text, font_size)
        !! Process LaTeX and render mixed-font text with mathtext support.
        type(pdf_context_core), intent(inout) :: ctx
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        real(wp), intent(in), optional :: font_size
        character(len=512) :: processed
        integer :: plen
        character(len=600) :: math_ready
        integer :: mlen

        ! Mathtext renders Unicode superscripts properly
        call process_latex_in_text(text, processed, plen)
        ! Mathtext engages only when callers supply explicit $...$ delimiters
        call prepare_mathtext_if_needed(processed(1:plen), math_ready, mlen)

        ! Route through mathtext renderer only when math segments are present
        if (has_mathtext(math_ready(1:mlen))) then
            if (present(font_size)) then
                call draw_pdf_mathtext(ctx, x, y, math_ready(1:mlen), font_size)
            else
                call draw_pdf_mathtext(ctx, x, y, math_ready(1:mlen))
            end if
        else
            if (present(font_size)) then
                call draw_mixed_font_text(ctx, x, y, processed(1:plen), font_size)
            else
                call draw_mixed_font_text(ctx, x, y, processed(1:plen))
            end if
        end if
    end subroutine render_mixed_text

    subroutine render_rotated_mixed_text(ctx, x, y, text)
        !! Process LaTeX and render rotated mixed-font ylabel with mathtext support.
        type(pdf_context_core), intent(inout) :: ctx
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        character(len=512) :: processed
        integer :: plen
        character(len=600) :: math_ready
        integer :: mlen

        ! Process LaTeX commands
        call process_latex_in_text(text, processed, plen)

        call prepare_mathtext_if_needed(processed(1:plen), math_ready, mlen)

        if (has_mathtext(math_ready(1:mlen))) then
            ! draw_pdf_mathtext doesn't support rotation; use text matrix approach
            call draw_rotated_pdf_mathtext(ctx, x, y, math_ready(1:mlen))
        else
            call draw_rotated_mixed_font_text(ctx, x, y, processed(1:plen))
        end if
    end subroutine render_rotated_mixed_text

    subroutine draw_rotated_pdf_mathtext(ctx, x, y, text)
        !! Draw rotated mathtext for ylabel using rotation matrix with manual text positioning
        use fortplot_pdf_text_segments, only: process_text_segments
        type(pdf_context_core), intent(inout) :: ctx
        real(wp), intent(in) :: x, y
        character(len=*), intent(in) :: text
        character(len=1024) :: matrix_cmd, td_cmd
        character(len=2048) :: preprocessed_text
        integer :: processed_len
        character(len=4096) :: math_ready
        integer :: mlen
        type(mathtext_element_t), allocatable :: elements(:)
        integer :: i
        real(wp) :: elem_font_size, elem_y_offset
        real(wp) :: char_width
        integer :: j, codepoint, char_len, text_len
        logical :: in_symbol_font

        ! Process text for mathtext
        call process_latex_in_text(text, preprocessed_text, processed_len)
        call preprocess_math_text(preprocessed_text(1:processed_len), math_ready, mlen)

        ! Parse mathtext elements
        elements = parse_mathtext(math_ready(1:mlen))

        ! Begin text object with rotation matrix (90 degrees counterclockwise)
        ctx%stream_data = ctx%stream_data//'BT'//new_line('a')

        ! Set rotation matrix: [0 1 -1 0 x y] for 90-degree rotation
        write (matrix_cmd, '("0 1 -1 0 ", F0.3, 1X, F0.3, " Tm")') x, y
        ctx%stream_data = ctx%stream_data//trim(adjustl(matrix_cmd))//new_line('a')

        ! Render each mathtext element with proper font size and vertical offset
        in_symbol_font = .false.
        do i = 1, size(elements)
            if (len_trim(elements(i)%text) > 0) then
                ! Calculate element font size and vertical offset
                elem_font_size = PDF_LABEL_SIZE*elements(i)%font_size_ratio
                elem_y_offset = elements(i)%vertical_offset*PDF_LABEL_SIZE

                ! Move to position for this element using Td (relative positioning)
                ! The rotation matrix transforms these:
                ! x->forward along text, y->perpendicular.
                if (i > 1) then
                    ! Move horizontally by previous element width, vertically by
                    ! offset difference.
                    write (td_cmd, '(F0.3, 1X, F0.3, " Td")') char_width, &
                        elem_y_offset - (elements(i - 1)%vertical_offset*PDF_LABEL_SIZE)
                    ctx%stream_data = &
                        ctx%stream_data//trim(adjustl(td_cmd))//new_line('a')
                else if (abs(elem_y_offset) > 0.01_wp) then
                    ! First element with non-zero offset
                    write (td_cmd, '("0 ", F0.3, " Td")') elem_y_offset
                    ctx%stream_data = &
                        ctx%stream_data//trim(adjustl(td_cmd))//new_line('a')
                end if

                ! Set font size for this element
                write (matrix_cmd, '("/F", I0, 1X, F0.1, " Tf")') &
                    ctx%fonts%get_helvetica_obj(), elem_font_size
                ctx%stream_data = &
                    ctx%stream_data//trim(adjustl(matrix_cmd))//new_line('a')

                ! Render text segments
                call process_text_segments(ctx, elements(i)%text, in_symbol_font, &
                                           elem_font_size)

                ! Calculate width for next element positioning
                char_width = 0.0_wp
                j = 1
                text_len = len_trim(elements(i)%text)
                do while (text_len < len(elements(i)%text))
                    if (elements(i)%text(text_len + 1:text_len + 1) == ' ') then
                        text_len = text_len + 1
                    else
                        exit
                    end if
                end do

                do while (j <= text_len)
                    char_len = utf8_char_length(elements(i)%text(j:j))
                    if (char_len == 0) then
                        codepoint = iachar(elements(i)%text(j:j))
                        char_len = 1
                    else
                        codepoint = utf8_to_codepoint(elements(i)%text, j)
                    end if

                    if (codepoint >= 48 .and. codepoint <= 57) then
                        char_width = char_width + elem_font_size*0.55_wp
                    else if (codepoint >= 65 .and. codepoint <= 90) then
                        char_width = char_width + elem_font_size*0.65_wp
                    else if (codepoint >= 97 .and. codepoint <= 122) then
                        char_width = char_width + elem_font_size*0.5_wp
                    else if (codepoint == 32) then
                        char_width = char_width + elem_font_size*0.3_wp
                    else
                        char_width = char_width + elem_font_size*0.5_wp
                    end if

                    j = j + char_len
                end do
            end if
        end do

        ctx%stream_data = ctx%stream_data//'ET'//new_line('a')
    end subroutine draw_rotated_pdf_mathtext

end module fortplot_pdf_axes_text
