"""
novelWriter – ToMd Class Tester
===============================

This file is a part of novelWriter
Copyright 2018–2024, Veronica Berglyd Olsen

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations

import pytest

from novelwriter.constants import nwHeadFmt
from novelwriter.core.project import NWProject
from novelwriter.formats.shared import BlockFmt, BlockTyp
from novelwriter.formats.tomarkdown import ToMarkdown


@pytest.mark.core
def testFmtToMarkdown_ConvertHeaders(mockGUI):
    """Test header formats in the ToMarkdown class."""
    project = NWProject()
    md = ToMarkdown(project, False)

    md._isNovel = True
    md._isFirst = True

    # Header 1
    md._text = "# Title\n"
    md.setPartitionFormat(f"Part{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "# Part - Title\n\n"

    # Header 2
    md._text = "## Title\n"
    md.setChapterFormat(f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "## Chapter 1 - Title\n\n"

    # Header 3
    md._text = "### Title\n"
    md.setSceneFormat(f"Scene {nwHeadFmt.SC_ABS}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "### Scene 1 - Title\n\n"

    # Header 4
    md._text = "#### Section Title\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "#### Section Title\n\n"

    # Title
    md._text = "#! Title\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "# Title\n\n"

    # Unnumbered
    md._text = "##! Prologue\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "## Prologue\n\n"


@pytest.mark.core
def testFmtToMarkdown_ConvertParagraphs(mockGUI):
    """Test paragraph formats in the ToMarkdown class."""
    project = NWProject()
    md = ToMarkdown(project, False)

    md._isNovel = True
    md._isFirst = True

    # Text for Extended Markdown
    md._extended = True
    md._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == (
        "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n\n"
    )

    # Text for Standard Markdown
    md._extended = False
    md._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == (
        "Some **nested bold and _italic_ and strikethrough text** here\n\n"
    )

    # Shortcodes for Extended Markdown
    md._extended = True
    md._text = (
        "Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
        "super[sup]script[/sup], sub[sub]script[/sub] here\n"
    )
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == (
        "Some **bold**, _italic_, ~~strike~~, underline, ==mark==, "
        "super^script^, sub~script~ here\n\n"
    )

    # Shortcodes for Standard Markdown
    md._extended = False
    md._text = (
        "Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
        "super[sup]script[/sup], sub[sub]script[/sub] here\n"
    )
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == (
        "Some **bold**, _italic_, strike, underline, mark, superscript, subscript here\n\n"
    )

    # Text w/Hard Break
    md._text = "Line one\nLine two\nLine three\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "Line one  \nLine two  \nLine three\n\n"

    # Text wo/Hard Break
    md._text = "Line one\nLine two\nLine three\n"
    md.setKeepLineBreaks(False)
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "Line one Line two Line three\n\n"

    # Synopsis, Short
    md._text = "%synopsis: The synopsis ...\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == ""

    md.setSynopsis(True)
    md._text = "%synopsis: The synopsis ...\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "**Synopsis:** The synopsis ...\n\n"

    md.setSynopsis(True)
    md._text = "%short: A description ...\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "**Short Description:** A description ...\n\n"

    # Comment
    md._text = "% A comment ...\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == ""

    md.setComments(True)
    md._text = "% A comment ...\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "**Comment:** A comment ...\n\n"

    # Keywords
    md._text = "@char: Bod, Jane\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == ""

    md.setKeywords(True)
    md._text = "@char: Bod, Jane\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "**Characters:** Bod, Jane\n\n"

    # Multiple Keywords
    md.setKeywords(True)
    md._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == (
        "## Chapter\n\n"
        "**Point of View:** Bod  \n"
        "**Plot:** Main  \n"
        "**Locations:** Europe\n\n"
    )

    # Footnotes
    md._text = (
        "Text with one[footnote:fa] or two[footnote:fb] footnotes.\n\n"
        "%footnote.fa: Footnote text A.\n\n"
    )
    md.tokenizeText()
    md.doConvert()
    assert md._pages[-1] == "Text with one[1] or two[ERR] footnotes.\n\n"

    md.closeDocument()
    assert md._pages[-2] == (
        "Text with one[1] or two[ERR] footnotes.\n\n"
    )
    assert md._pages[-1] == (
        "### Footnotes\n\n"
        "1. Footnote text A.\n\n"
    )


@pytest.mark.core
def testFmtToMarkdown_ConvertDirect(mockGUI):
    """Test the converter directly using the ToMarkdown class."""
    project = NWProject()
    md = ToMarkdown(project, False)
    md._isNovel = True

    # Special Titles
    # ==============

    # Title
    md._blocks = [
        (BlockTyp.TITLE, "", "A Title", [], BlockFmt.PBB | BlockFmt.CENTRE),
    ]
    md.doConvert()
    assert md._pages[-1] == "# A Title\n\n"

    # Separators
    # ==========

    # Separator
    md._blocks = [
        (BlockTyp.SEP, "", "* * *", [], BlockFmt.CENTRE),
    ]
    md.doConvert()
    assert md._pages[-1] == "* * *\n\n"

    # Skip
    md._blocks = [
        (BlockTyp.SKIP, "", "", [], BlockFmt.NONE),
    ]
    md.doConvert()
    assert md._pages[-1] == "\n\n"


@pytest.mark.core
def testFmtToMarkdown_Save(mockGUI, fncPath):
    """Test the save method of the ToMarkdown class."""
    project = NWProject()
    md = ToMarkdown(project, False)
    md._isNovel = True

    # Build Project
    # =============

    docText = [
        "# My Novel\n\n**By Jane Doh**\n",
        "## Chapter 1\n\nThe text of chapter one.\n",
        "### Scene 1\n\nThe text of scene one.\n",
        "#### A Section\n\nMore text in scene one.\n",
        "## Chapter 2\n\nThe text of chapter two.\n",
        "### Scene 2\n\nThe text of scene two.\n",
        "#### A Section\n\n\tMore text in scene two.\n",
    ]
    resText = [
        "# My Novel\n\n**By Jane Doh**\n\n",
        "## Chapter 1\n\nThe text of chapter one.\n\n",
        "### Scene 1\n\nThe text of scene one.\n\n",
        "#### A Section\n\nMore text in scene one.\n\n",
        "## Chapter 2\n\nThe text of chapter two.\n\n",
        "### Scene 2\n\nThe text of scene two.\n\n",
        "#### A Section\n\n\tMore text in scene two.\n\n",
    ]

    for i in range(len(docText)):
        md._text = docText[i]
        md.doPreProcessing()
        md.tokenizeText()
        md.doConvert()

    assert md._pages == resText
    assert md.getFullResultSize() == len("".join(resText))

    md.replaceTabs(nSpaces=4, spaceChar=" ")
    resText[6] = "#### A Section\n\n    More text in scene two.\n\n"
    assert md._pages == resText

    # Check File
    # ==========

    saveFile = fncPath / "outFile.md"
    md.saveDocument(saveFile)
    assert saveFile.read_text(encoding="utf-8") == "".join(resText)
