// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using System.Net;
using NUnit.Framework;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;

namespace osu.Game.Tests.Visual.Online
{
    public partial class TestSceneWikiOverlay : OsuTestScene
    {
        private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;

        private WikiOverlay wiki = null!;

        [SetUp]
        public void SetUp() => Schedule(() => Child = wiki = new WikiOverlay());

        [Test]
        public void TestMainPage()
        {
            setUpWikiResponse(responseMainPage);
            AddStep("Show main page", () => wiki.ShowPage());
        }

        [Test]
        public void TestCancellationDoesntShowError()
        {
            AddStep("Show main page", () => wiki.ShowPage());
            AddStep("Show another page", () => wiki.ShowPage("Article_styling_criteria/Formatting"));

            AddUntilStep("Current path is not error", () => wiki.CurrentPath != "error");
        }

        [Test]
        public void TestArticlePage()
        {
            setUpWikiResponse(responseArticlePage);
            AddStep("Show article page", () => wiki.ShowPage("Article_styling_criteria/Formatting"));
        }

        [Test]
        public void TestRedirection()
        {
            const string redirection_path = "Redirection_path_for_article";

            setUpWikiResponse(responseArticlePage, redirection_path);
            AddStep("Show article page", () => wiki.ShowPage(redirection_path));

            AddUntilStep("Current page is article", () => wiki.Header.Current.Value == "Formatting");

            setUpWikiResponse(responseArticleParentPage);
            AddStep("Show parent page", () => wiki.Header.ShowParentPage?.Invoke());

            AddUntilStep("Current page is parent", () => wiki.Header.Current.Value == "Article styling criteria");
        }

        [Test]
        public void TestErrorPage()
        {
            setUpWikiResponse(responseArticlePage);
            AddStep("Show nonexistent page", () => wiki.ShowPage("This_page_will_error_out"));
            AddUntilStep("Wait for error page", () => wiki.CurrentPath == "error");
            AddUntilStep("Error message correct", () => wiki.ChildrenOfType<SpriteText>().Any(text => text.Text == "\"This_page_will_error_out\"."));
        }

        [Test]
        public void TestReturnAfterErrorPage()
        {
            setUpWikiResponse(responseArticlePage);

            AddStep("Show article page", () => wiki.ShowPage("Article_styling_criteria/Formatting"));
            AddUntilStep("Wait for non-error page", () => wiki.CurrentPath == "Article_styling_criteria/Formatting");

            AddStep("Show nonexistent page", () => wiki.ShowPage("This_page_will_error_out"));
            AddUntilStep("Wait for error page", () => wiki.CurrentPath == "error");

            AddStep("Show article page", () => wiki.ShowPage("Article_styling_criteria/Formatting"));
            AddUntilStep("Wait for non-error page", () => wiki.CurrentPath == "Article_styling_criteria/Formatting");
            AddUntilStep("Error message not displayed", () => wiki.ChildrenOfType<SpriteText>().All(text => text.Text != "\"This_page_will_error_out\"."));
        }

        private void setUpWikiResponse(APIWikiPage r, string? redirectionPath = null)
            => AddStep("set up response", () =>
            {
                dummyAPI.HandleRequest = request =>
                {
                    if (!(request is GetWikiRequest getWikiRequest))
                        return false;

                    if (getWikiRequest.Path.Equals(r.Path, StringComparison.OrdinalIgnoreCase) ||
                        getWikiRequest.Path.Equals(redirectionPath, StringComparison.OrdinalIgnoreCase))
                    {
                        getWikiRequest.TriggerSuccess(r);
                    }
                    else
                        getWikiRequest.TriggerFailure(new WebException());

                    return true;
                };
            });

        // From https://osu.ppy.sh/api/v2/wiki/en/Main_page
        private APIWikiPage responseMainPage => new APIWikiPage
        {
            Title = "Main page",
            Layout = WikiOverlay.INDEX_PATH.ToLowerInvariant(), // custom classes are always lower snake.
            Path = WikiOverlay.INDEX_PATH,
            Locale = "en",
            Subtitle = null,
            Markdown =
                "---\nlayout: main_page\n---\n\n<!-- Do not add any empty lines inside this div. -->\n\n<div class=\"wiki-main-page__blurb\">\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n</div>\n\n<div class=\"wiki-main-page__panels\">\n<div class=\"wiki-main-page-panel wiki-main-page-panel--full\">\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n</div>\n<div class=\"wiki-main-page-panel\">\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n</div>\n</div>\n",
        };

        // From https://osu.ppy.sh/api/v2/wiki/en/Article_styling_criteria/Formatting
        private APIWikiPage responseArticlePage => new APIWikiPage
        {
            Title = "Formatting",
            Layout = "markdown_page",
            Path = "Article_styling_criteria/Formatting",
            Locale = "en",
            Subtitle = "Article styling criteria",
            Markdown =
                "# Formatting\n\n*For the writing standards, see: [Article style criteria/Writing](../Writing)*\\\n*Notice: This article uses [RFC 2119](https://tools.ietf.org/html/rfc2119) to describe requirement levels.*\n\n## Locales\n\nListed below are the properly-supported locales for the wiki:\n\n| File Name | Locale Name | Native Script |\n| :-- | :-- | :-- |\n| `en.md` | English | English |\n| `ar.md` | Arabic | \u0627\u064e\u0644\u0652\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629\u064f |\n| `be.md` | Belarusian | \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f \u043c\u043e\u0432\u0430 |\n| `bg.md` | Bulgarian | \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438 |\n| `cs.md` | Czech | \u010cesky |\n| `da.md` | Danish | Dansk |\n| `de.md` | German | Deutsch |\n| `el.md` | Greek | \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac |\n| `es.md` | Spanish | Espa\u00f1ol |\n| `fi.md` | Finnish | Suomi |\n| `fr.md` | French | Fran\u00e7ais |\n| `hu.md` | Hungarian | Magyar |\n| `id.md` | Indonesian | Bahasa Indonesia |\n| `it.md` | Italian | Italiano |\n| `ja.md` | Japanese | \u65e5\u672c\u8a9e |\n| `ko.md` | Korean | \ud55c\uad6d\uc5b4 |\n| `nl.md` | Dutch | Nederlands |\n| `no.md` | Norwegian | Norsk |\n| `pl.md` | Polish | Polski |\n| `pt.md` | Portuguese | Portugu\u00eas |\n| `pt-br.md` | Brazilian Portuguese | Portugu\u00eas (Brasil) |\n| `ro.md` | Romanian | Rom\u00e2n\u0103 |\n| `ru.md` | Russian | \u0420\u0443\u0441\u0441\u043a\u0438\u0439 |\n| `sk.md` | Slovak | Sloven\u010dina |\n| `sv.md` | Swedish | Svenska |\n| `th.md` | Thai | \u0e44\u0e17\u0e22 |\n| `tr.md` | Turkish | T\u00fcrk\u00e7e |\n| `uk.md` | Ukrainian | \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 |\n| `vi.md` | Vietnamese | Ti\u1ebfng Vi\u1ec7t |\n| `zh.md` | Chinese (Simplified) | \u7b80\u4f53\u4e2d\u6587 |\n| `zh-tw.md` | Traditional Chinese (Taiwan) | \u7e41\u9ad4\u4e2d\u6587\uff08\u53f0\u7063\uff09 |\n\n*Note: The website will give readers their selected language's version of an article. If it is not available, the English version will be given.*\n\n## Front matter\n\nFront matter must be placed at the very top of the file. It is written in [YAML](https://en.wikipedia.org/wiki/YAML#Example) and describes additional information about the article. This must be surrounded by three hyphens (`---`) on the lines above and below it, and an empty line must follow it before the title heading.\n\n### Articles that need help\n\n*Note: Avoid translating English articles with this tag. In addition to this, this tag should be added when the translation needs its own clean up.*\n\nThe `needs_cleanup` tag may be added to articles that need rewriting or formatting help. It is also acceptable to open an issue on GitHub for this purpose. This tag must be written as shown below:\n\n```yaml\nneeds_cleanup: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be done to remove the tag.\n\n### Outdated articles\n\n*Note: Avoid translating English articles with this tag. If the English article has this tag, the translation must also have this tag.*\n\nEnglish articles may become outdated when the content they contain is misleading or no longer relevant. These should receive an `outdated` tag, which must be written as shown below:\n\n```yaml\noutdated: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be updated to remove the tag.\n\n### Outdated translations\n\nTranslated articles that are outdated must use the `outdated_translation` tag when the English variant is updated, except for minor wording, grammar changes, and the like, that do not affect the meaning of the article.\n\n```yaml\noutdated_translation: true\n```\n\nWhen outdating translations, they must also receive an `outdated_since` tag that points to the first commit where the English version is updated.\n\n```yaml\noutdated_since: 29eac89cd535f8b071ca000af8fe4f0be22bdc9b\n```\n\n### Tagging articles\n\nTags help the website's search engine query articles better. Tags should be written in the same language as the article and include the original list of tags. Tags should use lowercase letters where applicable.\n\nFor example, an article called \"Beatmap discussion\" may include the following tags:\n\n```yaml\ntags:\n  - beatmap discussions\n  - modding V2\n  - MV2\n```\n\n### Translations without reviews\n\n*Note: Wiki maintainers will determine and apply this mark prior to merging.*\n\nSometimes, translations are added to the wiki without review from other native speakers of the language. In this case, the `no_native_review` mark is added to let future translators know that it may need to be checked again. This tag must be written as shown below:\n\n```yaml\nno_native_review: true\n```\n\n## Article naming\n\n*See also: [Folder names](#folder-names) and [Titles](#titles)*\n\nArticle titles should be singular and use sentence case. See [Wikipedia's naming conventions article](https://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(plurals)) for more details.\n\nArticle titles should match the folder name it is in (spaces may replace underscores (`_`) where appropriate). If the folder name changes, the article title should be changed to match it and vice versa.\n\n---\n\nContest and tournament articles are an exception. The folder name must use abbreviations, acronyms, or initialisms. The article's title must be the full name of the contest or tournament.\n\n## Folder and file structure\n\n### Folder names\n\n*See also: [Article naming](#article-naming)*\n\nFolder names must be in English and use sentence case.\n\nFolder names must only use these characters:\n\n- uppercase and lowercase letters\n- numbers\n- underscores (`_`)\n- hyphens (`-`)\n- exclamation marks (`!`)\n\n### Article file names\n\nThe file name of an article can be found in the `File Name` column of the [locales section](#locales). The location of a translated article must be placed in the same folder as the English article.\n\n### Index articles\n\nAn index article must be created if the folder is intended to only hold other articles. Index articles must contain a list of articles that are inside its own folder. They may also contain other information, such as a lead paragraph or descriptions of the linked articles.\n\n### Disambiguation articles\n\n[Disambiguation](/wiki/Disambiguation) articles must be placed in the `/wiki/Disambiguation` folder. The main page must be updated to include the disambiguation article. Refer to [Disambiguation/Mod](/wiki/Disambiguation/Mod) as an example.\n\nRedirects must be updated to have the ambiguous keyword(s) redirect to the disambiguation article.\n\nArticles linked from a disambiguation article must have a [For other uses](#for-other-uses) hatnote.\n\n## HTML\n\nHTML must not be used, with exception for [comments](#comments). The structure of the article must be redone if HTML is used.\n\n### Comments\n\nHTML comments should be used for marking to-dos, but may also be used to annotate text. They should be on their own line, but can be placed inline in a paragraph. If placed inline, the start of the comment must not have a space.\n\nBad example:\n\n```markdown\nHTML comments <!-- TODO explain HTML comments --> should be used for marking to-dos or annotate text.\n```\n\nGood example:\n\n```markdown\nHTML comments<!-- TODO explain HTML comments --> should be used for marking to-dos or annotate text.\n```\n\n## Editing\n\n### End of line sequence\n\n*Caution: Uploading Markdown files using `CRLF` (carriage return and line feed) via GitHub will result in those files using `CRLF`. To prevent this, set the line ending to `LF` (line feed) before uploading.*\n\nMarkdown files must be checked in using the `LF` end of line sequence.\n\n### Escaping\n\nMarkdown syntax should be escaped as needed. However, article titles are parsed as plain text and so must not be escaped.\n\n### Paragraphs\n\nEach paragraph must be followed by one empty line.\n\n### Line breaks\n\nLine breaks must use a backslash (`\\`).\n\nLine breaks must be used sparingly.\n\n## Hatnote\n\n*Not to be confused with [Notice](#notice).*\n\nHatnotes are short notes placed at the top of an article or section to help readers navigate to related articles or inform them about related topics.\n\nHatnotes must be italicised and be placed immediately after the heading. If multiple hatnotes are used, they must be on the same paragraph separated with a line break.\n\n### Main page\n\n*Main page* hatnotes direct the reader to the main article of a topic. When this hatnote is used, it implies that the section it is on is a summary of what the linked page is about. This hatnote should have only one link. These must be formatted as follows:\n\n```markdown\n*Main page: {article}*\n\n*Main pages: {article} and {article}*\n```\n\n### See also\n\n*See also* hatnotes suggest to readers other points of interest from a given article or section. These must be formatted as follows:\n\n```markdown\n*See also: {article}*\n\n*See also: {article} and {article}*\n```\n\n### For see\n\n*For see* hatnotes are similar to *see also* hatnotes, but are generally more descriptive and direct. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*For {description}, see: {article}*\n\n*For {description}, see: {article} and {article}*\n```\n\n### Not to be confused with\n\n*Not to be confused with* hatnotes help distinguish ambiguous or misunderstood article titles or sections. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*Not to be confused with {article}.*\n\n*Not to be confused with {article} or {article}.*\n```\n\n### For other uses\n\n*For other uses* hatnotes are similar to *not to be confused with* hatnotes, but links directly to the [disambiguation article](#disambiguation-articles). This hatnote must only link to the disambiguation article. These must be formatted as follows:\n\n```markdown\n*For other uses, see {disambiguation article}.*\n```\n\n## Notice\n\n*Not to be confused with [Hatnote](#hatnote).*\n\nA notice should be placed where appropriate in a section, but must start off the paragraph and use italics. Notices may contain bolding where appropriate, but should be kept to a minimum. Notices must be written as complete sentences. Thus, unlike most [hatnotes](#hatnote), notices must use a full stop (`.`) or an exclamation mark (`!`) if appropriate. Anything within the same paragraph of a notice must also be italicised. These must be formatted as follows:\n\n```markdown\n*Note: {note}.*\n\n*Notice: {notice}.*\n\n*Caution: {caution}.*\n\n*Warning: {warning}.*\n```\n\n- `Note` should be used for factual or trivial details.\n- `Notice` should be used for reminders or to draw attention to something that the reader should be made aware of.\n- `Caution` should be used to warn the reader to avoid unintended consequences.\n- `Warning` should be used to warn the reader that action may be taken against them.\n\n## Stacked hatnotes and notices\n\nMultiple hatnotes and notices may be stacked when necessary. When doing this, they must be stacked without blank lines and use trailing backslashes:\n\n```markdown\n*Warning: {warning}.*\\\n*See also: {article}*\n```\n\nIn many cases, it may be more fitting to embed extraneous hatnotes or notices into paragraph text instead of stacking many of them.\n\n## Emphasising\n\n### Bolding\n\nBold text must use double asterisks (`**`).\n\nLead paragraphs may bold the first occurrence of the article's title.\n\n### Italics\n\nItalics must use single asterisks (`*`).\n\nThe first occurrence of an abbreviation, acronym, or initialism may be italicised.\n\nItalics may also be used to provide emphasis or help with readability.\n\nNames of work or video games should be italicised. osu! \u2014 the game \u2014 is exempt from this.\n\nAs an example, when referring to songs in the format of `{artist} - {title}`, the whole part is a reference to the work and should therefore be italicised:\n\n```markdown\n*cYsmix - triangles* is a one of the three intro songs that can be heard when starting the game client.\n```\n\nArtist names are otherwise generally not italicised. This means that in free-form references, only the title should be italicised, because the artist name is then not part of the name of the work:\n\n```markdown\n*Blue Zenith* by xi is an infamous song in the osu! community due to a famous score set by a top player on a certain beatmap.\n```\n\n### Emphasis and links\n\nLinked text appears in a different colour which already provides emphasis, and therefore does not need further emphasis:\n\n```markdown\n[Camellia - OOPARTS](https://cametek.bandcamp.com/track/parts) is an example of a song officially created specifically for osu!, otherwise known as an *osu! original*, since it was specifically commissioned for the osu! World Cup 2020 tiebreaker.\n```\n\nThis however does not apply if the referenced work is not the only part of the link:\n\n```markdown\n[Voltaeyx's beatmap of *TheFatRat - Mayday (feat. Laura Brehm)*](https://osu.ppy.sh/beatmapsets/756794) amassed considerable popularity in 2018 due to its unique overlapping slider patterns.\n```\n\nThe above type of construction should be used sparingly, and must not be used in places with many links, such as tables or lists.\n\n## Headings\n\nAll headings must use sentence case.\n\nHeadings must use the [ATX (hash) style](https://github.github.com/gfm/#atx-headings) and must have an empty line before and after the heading. The title heading is an exception when it is on the first line. If this is the case, there only needs to be an empty line after the title heading.\n\nHeadings must not exceed a heading level of 5 and must not be used to style or format text.\n\n### Titles\n\n*See also: [Article naming](#article-naming)*\\\n*Caution: Titles are parsed as plain text; they must not be escaped.*\n\nThe first heading in all articles must be a level 1 heading, being the article's title. All headings afterwards must be [section headings](#sections). Titles must not contain formatting, links, or images.\n\nThe title heading must be on the first line, unless [front matter](#front-matter) is being used. If that is the case, the title heading must go after it and have an empty line before the title heading.\n\n### Sections\n\nSection headings must use levels 2 to 5. The section heading proceeding the [title heading](#titles) must be a level 2 heading. Unlike titles, section headings may have small image icons.\n\nSection headings must not skip a heading level (i.e. do not go from a level 2 heading to a level 4 heading) and must not contain formatting or links.\n\n*Notice: On the website, heading levels 4 and 5 will not appear in the table of contents.*\n\n### Custom identifiers\n\nIt is possible to redefine a section's identifier, which is used for linking to it directly. Custom identifiers should be used in case the automatically generated ones are too long or contain tricky punctuation marks or images:\n\n<!-- TODO: remove the {id=...} example when https://github.com/ppy/osu-web/issues/8057 is closed -->\n\n```markdown\n## My cooldown has passed. How do I appeal? {#appeal}\n\n## Common restriction reasons and cooldowns {#common-reasons}\n\n## Ideas for a multiplayer match {id=\u0438\u0434\u0435\u0438-\u0434\u043b\u044f-\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u0430} <!-- alternative syntax for Unicode identifiers -->\n```\n\nThis feature can also be used for tagging a specific part of the article which doesn't have a heading. Use it sparingly:\n\n```markdown\n> That's it! You're well on your way to becoming an osu! rhythm champion!\n{#tutorial-quote}\n```\n\n## Lists\n\nLists should not go over 4 levels of indentation and should not have an empty line in between each item.\n\nFor nested lists, bullets or numbers must align with the item content of their parent lists.\n\nThe following example was done incorrectly (take note of the spacing before the bullet):\n\n```markdown\n1. Fly a kite\n  - Don't fly a kite if it's raining\n```\n\nThe following example was done correctly:\n\n```markdown\n1. Fly a kite\n   - Don't fly a kite if it's raining\n```\n\n### Bulleted\n\nBulleted lists must use a hyphen (`-`). These must then be followed by one space. (Example shown below.)\n\n```markdown\n- osu!\n  - Hit circle\n    - Combo number\n    - Approach circle\n  - Slider\n    - Hit circles\n    - Slider body\n    - Slider ticks\n  - Spinner\n- osu!taiko\n```\n\n### Numbered\n\nThe numbers in a numbered list must be incremented to represent their step.\n\n```markdown\n1. Download the osu! installer.\n2. Run the installer.\n   1. To change the installation location, click the text underneath the progression bar.\n   2. The installer will prompt for a new location, choose the installation folder.\n3. osu! will start up once installation is complete.\n4. Sign in.\n```\n\n### Mixed\n\nCombining both bulleted and numbered lists should be done sparingly.\n\n```markdown\n1. Download a skin from the forums.\n2. Load the skin file into osu!.\n   - If the file is a `.zip`, unzip it and move the contents into the `Skins/` folder (found in your osu! installation folder).\n   - If the file is a `.osk`, open it on your desktop or drag-and-drop it into the game client.\n3. Open osu!, if it is not opened, and select the skin in the options.\n   - This may have been completed if you opened the `.osk` file or drag-and-dropped it into the game client.\n```\n\n## Code\n\nThe markup for code is a grave mark (`` ` ``). To put grave marks in code, use double grave marks instead. If the grave mark is at the start or end, pad it with one space. (Example shown below.)\n\n```markdown\n`` ` ``\n`` `Space` ``\n```\n\n### Keyboard keys\n\n*Notice: When denoting the letter itself, and not the keyboard key, use quotation marks instead.*\n\nWhen representing keyboard keys, use capital letters for single characters and title case for modifiers. Use the plus symbol (`+`) (without code) to represent key combinations. (Example shown below.)\n\n```markdown\npippi is spelt with a lowercase \"p\" like peppy.\n\nPress `Ctrl` + `O` to open the open dialog.\n```\n\nWhen representing a space or the spacebar, use `` `Space` ``.\n\n### Button and menu text\n\nWhen copying the text from a menu or button, the letter casing should be copied as it appears. (Example shown below.)\n\n```markdown\nThe `osu!direct` button is visible in the main menu on the right side, if you have an active osu!supporter tag.\n```\n\n### Folder and directory names\n\nWhen copying the name of a folder or directory, the letter casing should be copied as it appears, but prefer lowercased paths when possible. Directory paths must not be absolute (i.e. do not start the directory name from the drive letter or from the root folder). (Example shown below.)\n\n```markdown\nosu! is installed in the `AppData/Local` folder by default, unless specified otherwise during installation.\n```\n\n### Keywords and commands\n\nWhen copying a keyword or command, the letter casing should be copied as it appears or how someone normally would type it. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nAs of now, the `Name` and `Author` commands in the skin configuration file (`skin.ini`) do nothing.\n```\n\n### File names\n\nWhen copying the name of a file, the letter casing should be copied as it appears. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nTo play osu!, double click the `osu!.exe` icon.\n```\n\n### File extensions\n\n*Notice: File formats (not to be confused with file extensions) must be written in capital letters without the prefixed fullstop (`.`).*\n\nFile extensions must be prefixed with a fullstop (`.`) and be followed by the file extension in lowercase letters. (Example shown below.)\n\n```markdown\nThe JPG (or JPEG) file format has the `.jpg` (or `.jpeg`) extension.\n```\n\n### Chat channels\n\nWhen copying the name of a chat channel, start it with a hash (`#`), followed by the channel name in lowercase letters. (Example shown below.)\n\n```markdown\n`#lobby` is where you can advertise your multi room.\n```\n\n## Preformatted text (code blocks)\n\n*Notice: Syntax highlighting for preformatted text is not implemented on the website yet.*\n\nPreformatted text (also known as code blocks) must be fenced using three grave marks. They should set the language identifier for syntax highlighting.\n\n## Links\n\n*See also: [Footnotes](#footnotes)*\n\nThere are two types of links: inline and reference. Inline has two styles.\n\nThe following is an example of both inline styles:\n\n```markdown\n[Game modifier](/wiki/Game_modifier)\n\n<https://osu.ppy.sh/home>\n```\n\nThe following is an example of the reference style:\n\n```markdown\n[Game modifier][game mods link]\n\n[game mods link]: /wiki/Game_modifier\n```\n\n---\n\nLinks must use the inline style if they are only referenced once. The inline angle brackets style should be avoided. References to reference links must be placed at the bottom of the article.\n\n### Internal links\n\n*Note: Internal links refer to links that stay inside the `https://osu.ppy.sh/` domain.*\n\n#### Wiki links\n\nAll links that point to an wiki article should start with `/wiki/` followed by the path to get to the article you are targeting. Relative links may also be used. Some examples include the following:\n\n```markdown\n[FAQ](/wiki/FAQ)\n[pippi](/wiki/Mascots#pippi)\n[Beatmaps](../)\n[Pattern](./Pattern)\n```\n\nWiki links must not use redirects and must not have a trailing forward slash (`/`).\n\nBad examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/ASC)\n[Developers](/wiki/Developers/)\n[Developers](/wiki/Developers/#game-client-developers)\n```\n\nGood examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/Article_styling_criteria)\n[Developers](/wiki/People/The_Team/Developers)\n[Developers](/wiki/People/The_Team/Developers#game-client-developers)\n```\n\n##### Sub-article links\n\nWiki links that point to a sub-article should include the parent article's folder name in its link text. See the following example:\n\n```markdown\n*See also: [Beatmap Editor/Design](/wiki/Client/Beatmap_editor/Design)*\n```\n\n##### Section links\n\n*Notice: On the website, heading levels 4 and 5 are not given the id attribute. This means that they can not be linked to directly.*\n\nWiki links that point to a section of an article may use the section sign symbol (`\u00a7`). See the following example:\n\n```markdown\n*For timing rules, see: [Ranking Criteria \u00a7 Timing](/wiki/Ranking_Criteria#timing)*\n```\n\n#### Other osu! links\n\nThe URL from the address bar of your web browser should be copied as it is when linking to other osu! web pages. The `https://osu.ppy.sh` part of the URL must be kept.\n\n##### User profiles\n\nAll usernames must be linked on first occurrence. Other occurrences are optional, but must be consistent throughout the entire article for all usernames. If it is difficult to determine the user's id, it may be skipped over.\n\nWhen linking to a user profile, the user's id number must be used. Use the new website (`https://osu.ppy.sh/users/{username})`) to get the user's id.\n\nThe link text of the user link should be the user's current name.\n\n##### Difficulties\n\nWhenever linking to a single difficulty, use this format as the link text:\n\n```\n{artist} - {title} ({creator}) [{difficulty_name}]\n```\n\nThe link must actually link to that difficulty. Beatmap difficulty URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}#{mode}/{BeatmapID}\n```\n\nThe difficulty name may be left outside of the link text, but doing so must be consistent throughout the entire article.\n\n##### Beatmaps\n\nWhenever linking to a beatmap, use this format as the link text:\n\n```\n{artist} - {title} ({creator})\n```\n\nAll beatmap URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}\n```\n\n### External links\n\n*Notice: External links refers to links that go outside the `https://osu.ppy.sh/` domain.*\n\nThe `https` protocol must be used, unless the site does not support it. External links must be a clean and direct link to a reputable source. The URL from the address bar of your web browser should be copied as it is when linking to other external pages.\n\nThere are no visual differences between external and osu! web links. Due to this, the website name should be included in the title text. See the following example:\n\n```markdown\n*For more information about music theory, see: [Music theory](https://en.wikipedia.org/wiki/Music_theory)*\n```\n\n## Images\n\nThere are two types of image links: inline and reference. Examples:\n\n**Inline style:**\n\n```markdown\n![Gold crown](/wiki/shared/crown-gold.png \"1st place\")\n```\n\n**Reference style:**\n\n```markdown\n![Gold crown][GCrown]\n\n[GCrown]: /wiki/shared/crown-gold.png \"1st place\"\n```\n\nImages should use the inline linking style. Reference link definitions must be placed at the bottom of the article.\n\nAll block images on the page (that have nothing else on the same line) are combined into a single gallery, which can be navigated using arrow icons on both sides of the screen, keyboard shortcuts, or screen swipes on mobile devices<!-- https://github.com/ppy/osu-web/pull/8126 -->.\n\n### Alternative and title text\n\nThe text in the first pair of square brackets (*alternative text*) should describe the image literally. It is used by screen readers or when the image fails to load. It can be omitted if it is identical to the title text or if the image is included only for decorative purposes.\n\nThe text in the quotation marks (*title text*) should give additional context to the image or indicate its meaning. It is displayed as a tooltip when hovering over the image and used as a caption if applicable. It does not support any markdown formatting.\n\n### Display\n\nIf an image is the sole content of a paragraph, it displays as a centred block. Otherwise, it flows with the surrounding inline text.\n\nBlock images with title text display the title text as a caption below the image. Avoid adding [HTML comment](#comments) or any other text on the same line as the image, as this will cause the caption not to be rendered.\n\nBlock images are commonly paired with [infobox](#infoboxes) formatting to reduce their initial size and float them to the side of other content:\n\n```markdown\n::: Infobox\n![](img/mod-response.png \"An example of a response to a mod\")\n:::\n```\n\n### Image caching\n\nImages on the website are cached for up to 60 days. The cached image is matched with the image link's URL.\n\nWhen updating an image, either change the image's name or append a query string to the URL. In both cases, all translations linking to the updated image should also be updated.\n\n### Formats and quality\n\nImages should use the JPG format at quality 8 (80 or 80%, depending on the program). If the image contains transparency or has text that must be readable, use the PNG format instead. If the image contains an animation, the GIF format can be used; however, this should be used sparingly as these may take longer to load or can be bigger then the [max file size](#file-size).\n\n### File size\n\nImages must be under 1 megabyte, otherwise they will fail to load. Downscaling and using JPG at 80% is almost always under the size limit.\n\nAll images should be optimised as much as possible. Use [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive) to compress JPEG images. For consistency, use the following command for jpeg-archive:\n\n```sh\njpeg-recompress -am smallfry <input> <output>\n```\n\nWhere `<input>` is the file name to be compressed and `<output>` is the compressed file name.\n\n### File names\n\n*Notice: File extensions must use lowercase letters, otherwise they will fail to load!*\n\nUse hyphens (`-`) when spacing words. When naming an image, the file name should be meaningful or descriptive but short.\n\nImages must be placed in a folder named `img` under the article's folder. Images that are used in multiple articles should be stored in the `/wiki/shared` folder.\n\n### Max image width\n\nThe website's max image width is the width of the article body. Images should be no wider than 800 pixels.\n\n### Annotating images\n\nWhen annotating images, use *Torus Regular*. For Chinese, Korean, Japanese characters, use *Microsoft YaHei*.\n\nAnnotating images should be avoided, as it is difficult for translators (and other editors) to edit them.\n\n#### Translating annotated images\n\nWhen translating annotated images, the localised image version must be placed in the same directory as the original version (i.e. the English version). The filename of a localised image version must start with the original version's name, followed by a hyphen, followed by the locale name (in capital letters). See the following examples:\n\n- `hardrock-mod-vs-easy-mod.jpg` for English\n- `hardrock-mod-vs-easy-mod-DE.jpg` for German\n- `hardrock-mod-vs-easy-mod-ZH-TW.jpg` for Traditional Chinese\n\n### Screenshots of gameplay\n\nAll screenshots of gameplay must be done in the stable build, unless it is for a specific feature that is unavailable in the stable build. You should use the in-game screenshot feature (`F12`).\n\n#### Game client settings\n\n*Note: If you do not want to change your current settings for the wiki, you can move your `osu!.<ComputerUser>.cfg` out of the osu! folder and move it back later.*\n\nYou must set these settings before taking a screenshot of the game client (settings not stated below are assumed to be at their defaults):\n\n- Select language: `English`\n- Prefer metadata in original language: `Enabled`\n- Resolution: `1280x720`\n- Fullscreen mode: `Disabled`\n- Parallax: `Disabled`\n- Menu tips: `Disabled`\n- Seasonal backgrounds: `Never`\n- Always show key overlay: `Enabled`\n- Current skin: `Default` (first option)\n\n*Notice to translators: If you are translating an article containing screenshots of the game, you may set the game client's language to the language you are translating in.*\n\n### Image links\n\nImages must not be part of a link text.\n\n## Flag icons\n\nThe flag icons use the two letter code (in all capital letters) to match a certain territory. When adding a flag inline, use this format:\n\n```markdown\n::{ flag=XX }::\n```\n\nWhere `XX` is the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) two-lettered country code for the flag.\n\n## Tables\n\nTables on the website only support headings along the first row.\n\nTables must not be beautified (do not pad cells with extra spaces to make their widths uniform). They must have a vertical bar (`|`) on the left and right sides and the text of each cell must be padded with one space on both sides. Empty cells must use a vertical bar (`|`) followed by two spaces then another vertical bar (`|`).\n\nThe delimiter row (the next line after the table heading) must use only three characters per column (and be padded with a space on both sides), which must look like one of the following:\n\n- `:--` (for left align)\n- `:-:` (for centre align)\n- `--:` (for right align)\n\n---\n\nThe following is an example of what a table should look like:\n\n```markdown\n| Team \"Picturesque\" Red | Score | Team \"Statuesque\" Blue | Average Beatmap Stars |\n| :-- | :-: | --: | :-- |\n| **peppy** | 5 - 2 | pippi | 9.3 stars |\n| Aiko | 1 - 6 | **Alisa** | 4.2 stars |\n| Ry\u016bta | 3 - 4 | **Yuzu** | 5.1 stars |\n| **Taikonator** | 7 - 0 | Tama | 13.37 stars |\n| Maria | No Contest | Mocha |  |\n```\n\n## Infoboxes\n\nAn infobox is a fixed-width block which is aligned to the right side of the article. It may contain a relevant image, which explains the surrounding text, or a block of navigation that links to other articles from the same category.\n\nExample use, rendered on the right:\n\n<!-- The real infobox is added for illustrative purposes, with Markdown syntax duplicated below for clarity. -->\n\n::: Infobox\n![](/wiki/shared/mods/SD.png \"Sudden Death mod icon\")\n:::\n\n```markdown\n::: Infobox\n![](/wiki/shared/mods/SD.png \"Sudden Death mod icon\")\n:::\n```\n\nInfoboxes should be used with caution in the following cases:\n\n- Short sections: the next section's heading appears below any infoboxes, leaving a large gap after the text.\n- Several images at once: instead, use individual infoboxes for better design.\n\n## Footnotes\n\nFootnotes are short notes located at the end of the page. They are used for citing sources, or providing background information that would otherwise disrupt the flow of the article. Footnotes may contain text formatting and links.\n\nIn the osu! wiki, footnotes are implemented using special syntax (`[^identifier]`). Footnotes can use any identifier, but they will automatically be rendered as superscripts with increasing numbers in order of their first appearance. Translations must not modify identifiers of footnotes.\n\nFootnote references are placed directly after the words, phrases, or sentences they explain, with no space in between. These references must be placed after punctuation, except for parentheses, when they pertain to the contents inside, and dashes.<!-- Taken from https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style#Punctuation_and_footnotes -->\n\nThe footnotes themselves must be placed in a separate second-level heading at the end of the article. Depending on the content, the heading used may be `References`, `Notes`, or `Notes and references`.\n\nCorrect usage examples:\n\n```markdown\nThe osu! wiki is a project that was meant to replace the old FAQ system.[^wiki-faq] It was named after the rhythm game osu![^osu] and the largest open online encyclopedia, Wikipedia. From the very start, it had attracted skillful translators[^wiki-tl] and editors.\n\n## References\n\n[^wiki-faq]: https://osu.ppy.sh/community/forums/topics/68525\n[^wiki-tl]: https://osu.ppy.sh/community/forums/posts/1177500\n[^osu]: https://osu.ppy.sh/community/forums/posts/1178153\n```\n\n### Citations\n\nCitations, or references, are used to identify a source of information. Citations via footnotes should be preferred over inline links.\n\nReferences should whenever applicable specify author, date, service/platform, and title. The exact format may vary depending on the referenced material with a preference for brevity.\n\nExamples:\n\n```markdown\nThe first version of the osu!api was made available on July 2, 2013.[^api-first-usage] It had received critical acclaim from users.[^api-praise] A new version of API, released several years later, contains many more capabilities.[^api-v2-2020] Endpoint versioning is common among web APIs.[^web-api]\n\n## References\n\n[^api-first-usage]: [Forum thread by peppy (2013-07-02) \"osu!api open beta\"](https://osu.ppy.sh/community/forums/posts/2403913)\n[^api-praise]: [Forum post by Menchi (2013-11-02) in \"osu!api open beta\"](https://osu.ppy.sh/community/forums/posts/2662247)\n[^api-v2-2020]: [Tweet by @ppy (2020-03-20)](https://twitter.com/ppy/status/1263083636363948032)\n[^web-api]: [\"Web API\" on Wikipedia](https://en.wikipedia.org/wiki/Web_API)\n```\n\n### Notes\n\nFootnotes may be used for storing explanations or tangential remarks which cannot be inlined without worsening the article's readability, or are less significant than the article itself. Such footnotes may use free-form text.\n\nExample:\n\n```markdown\nA tournament must not be organised and run by an inexperienced team of unaccomplished and irreputable staff.[^staff]\n\n## Notes\n\n[^staff]: An *inexperienced* staff member is loosely defined as someone who has been playing osu! for less than an hour in total.\n```\n\n## Blockquotes\n\nThe blockquote is limited to [quoting someone or something](/wiki/Article_styling_criteria/Writing#block-quotation). It must not be used to format text otherwise.\n\n```markdown\n> plz enjoy game\n\n\u2014rrtyui\n```\n\n## Thematic breaks\n\nThe thematic break (also known as the horizontal rule or line) should be used sparingly. A few uses of the thematic break may include (but is not limited to):\n\n- separating images from text\n- separating multiple images that follow one another\n- shifting the topic within a section\n\nThese must have an empty line before and after the markup. Thematic breaks must use only three hyphens, as depicted below:\n\n```markdown\n---\n```\n"
        };

        // From https://osu.ppy.sh/api/v2/wiki/en/Article_styling_criteria
        private APIWikiPage responseArticleParentPage => new APIWikiPage
        {
            Title = "Article styling criteria",
            Layout = "markdown_page",
            Path = "Article_styling_criteria",
            Locale = "en",
            Subtitle = null,
            Markdown =
                "---\ntags:\n  - wiki standards\n---\n\n# Article styling criteria\n\n*For news posts, see: [News Styling Criteria](/wiki/News_styling_criteria)*\n\nThe article styling criteria (ASC) serve as the osu! wiki's enforced styling standards to keep consistency in clarity, formatting, and layout in all articles, and to help them strive for proper grammar, correct spelling, and correct information.\n\nThese articles are primarily tools to aid in reviewing and represent the consensus of osu! wiki contributors formed over the years. Since the wiki is a collaborative effort through the review process, it is not necessary to read or memorise all of the ASC at once. If you are looking to contribute, read the [contribution guide](/wiki/osu!_wiki/Contribution_guide).\n\nTo suggest changes regarding the article styling criteria, [open an issue on GitHub](https://github.com/ppy/osu-wiki/issues/new).\n\n## Standards\n\n*Notice: The articles below use [RFC 2119](https://tools.ietf.org/html/rfc2119) to describe requirement levels.*\n\nThe article styling criteria are split up into two articles:\n\n- [Formatting](Formatting): includes Markdown and other formatting rules\n- [Writing](Writing): includes writing practices and other grammar rules\n"
        };
    }
}
