import json
import os
from collections import OrderedDict

import pytest

import great_expectations as gx
from great_expectations import DataContext
from great_expectations.core import ExpectationConfiguration, ExpectationSuite
from great_expectations.core.expectation_validation_result import (
    ExpectationSuiteValidationResultSchema,
)
from great_expectations.render import (
    RenderedDocumentContent,
    RenderedHeaderContent,
    RenderedSectionContent,
    RenderedTableContent,
)
from great_expectations.render.renderer import (
    ExpectationSuitePageRenderer,
    ValidationResultsPageRenderer,
)
from great_expectations.render.renderer_configuration import MetaNotesFormat
from great_expectations.render.view import DefaultMarkdownPageView
from great_expectations.validation_operators.types.validation_operator_result import (
    ValidationOperatorResult,
)


@pytest.fixture()
def validation_operator_result():
    fixture_filename = os.path.join(
        os.path.dirname(__file__),
        "fixtures/ValidationOperatorResult_with_multiple_validation_results.json",
    )
    with open(fixture_filename) as infile:
        validation_operator_result = json.load(infile, object_pairs_hook=OrderedDict)
        run_results = validation_operator_result["run_results"]
        for k, validation_result in run_results.items():
            validation_result[
                "validation_result"
            ] = ExpectationSuiteValidationResultSchema().load(
                validation_result["validation_result"]
            )
        return validation_operator_result


@pytest.fixture()
def expectation_suite_to_render_with_notes(empty_data_context):
    context: DataContext = empty_data_context
    expectation_suite = ExpectationSuite(
        expectation_suite_name="default",
        meta={"great_expectations_version": "0.13.0-test"},
        expectations=[
            ExpectationConfiguration(
                expectation_type="expect_column_to_exist",
                kwargs={"column": "infinities"},
            ),
            ExpectationConfiguration(
                expectation_type="expect_column_to_exist", kwargs={"column": "nulls"}
            ),
            ExpectationConfiguration(
                expectation_type="expect_column_to_exist", kwargs={"column": "naturals"}
            ),
            ExpectationConfiguration(
                expectation_type="expect_column_distinct_values_to_be_in_set",
                kwargs={"column": "irrationals", "value_set": ["*", "1st", "2nd"]},
            ),
            ExpectationConfiguration(
                expectation_type="expect_column_values_to_be_unique",
                kwargs={"column": "testings"},
                meta={
                    "notes": {
                        "content": [
                            "Example notes about this expectation. **Markdown** `Supported`.",
                            "Second example note **with** *Markdown*",
                        ],
                        "format": MetaNotesFormat.MARKDOWN,
                    }
                },
            ),
        ],
        data_context=context,
    )
    return expectation_suite


def test_render_section_page():
    section = RenderedSectionContent(
        **{
            "section_name": None,
            "content_blocks": [
                RenderedHeaderContent(
                    **{
                        "content_block_type": "header",
                        "header": "Overview",
                    }
                ),
                RenderedTableContent(
                    **{
                        "content_block_type": "table",
                        "header": "Dataset info",
                        "table": [
                            ["Number of variables", "12"],
                            ["Number of observations", "891"],
                        ],
                        "styling": {
                            "classes": ["col-6", "table-responsive"],
                            "styles": {"margin-top": "20px"},
                            "body": {"classes": ["table", "table-sm"]},
                        },
                    }
                ),
            ],
        }
    )

    rendered_doc = gx.render.view.view.DefaultMarkdownPageView().render(
        RenderedDocumentContent(sections=[section])
    )

    rendered_doc = rendered_doc.replace(" ", "").replace("\t", "").replace("\n", "")

    assert (
        rendered_doc
        == """
        #ValidationResults
        ##Overview
        ###Datasetinfo
        ||||------------|------------|Numberofvariables|12Numberofobservations|891
        -----------------------------------------------------------
        Poweredby[GreatExpectations](https://greatexpectations.io/)
        """.replace(
            " ", ""
        )
        .replace("\t", "")
        .replace("\n", "")
    )


def test_snapshot_render_section_page_with_fixture_data(validation_operator_result):
    """
    Make sure the appropriate markdown rendering is done for the applied fixture.
    Args:
        validation_operator_result: test fixture

    Returns: None

    """
    validation_operator_result = ValidationOperatorResult(**validation_operator_result)

    validation_results_page_renderer = ValidationResultsPageRenderer(
        run_info_at_end=True
    )

    rendered_document_content_list = (
        validation_results_page_renderer.render_validation_operator_result(
            validation_operator_result=validation_operator_result
        )
    )

    md_str_list = DefaultMarkdownPageView().render(rendered_document_content_list)

    md_str = " ".join(md_str_list)

    md_str = md_str.replace(" ", "").replace("\t", "").replace("\n", "")

    assert (
        md_str
        == """
# Validation Results
## Overview
### **Expectation Suite:** **basic.warning**
**Data asset:** **None**
**Status:**  **Failed**
### Statistics
 |  |  |
 | ------------  | ------------ |
Evaluated Expectations  | 11
Successful Expectations  | 9
Unsuccessful Expectations  | 2
Success Percent  | ≈81.82%
## Table-Level Expectations
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
❌  | Must have greater than or equal to **27000** and less than or equal to **33000** rows.  | 30
✅  | Must have exactly **3** columns.  | 3
✅  | Must have these columns in this order: **Team**, ** "Payroll (millions)"**, ** "Wins"**  | ['Team', ' "Payroll (millions)"', ' "Wins"']
##  "Payroll (millions)"
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | minimum value must be greater than or equal to **54.24** and less than or equal to **56.24**.  | 55.24
✅  | maximum value must be greater than or equal to **196.96** and less than or equal to **198.96**.  | 197.96
✅  | mean must be greater than or equal to **97.01899999999998** and less than or equal to **99.01899999999998**.  | ≈98.019
❌  | median must be greater than or equal to **84000.75** and less than or equal to **86000.75**.  | 85.75
✅  | quantiles must be within the following value ranges.
 | Quantile | Min Value | Max Value |
 | ------------  | ------------  | ------------ |
0.05  | 54.37  | 56.37
Q1  | 74.48  | 76.48
Median  | 82.31  | 84.31
Q3  | 116.62  | 118.62
0.95  | 173.54  | 175.54
  |
 | Quantile | Value |
 | ------------  | ------------ |
0.05  | 55.37
Q1  | 75.48
Median  | 83.31
Q3  | 117.62
0.95  | 174.54
## Team
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | values must always be greater than or equal to **1** characters long.  | 0% unexpected
### Info
 |  |  |
 | ------------  | ------------ |
Great Expectations Version  | 0.11.8+4.g4ab34df3.dirty
Run Name  | getest run
Run Time  | 2020-07-27T17:19:32Z
### Batch Markers
 |  |  |
 | ------------  | ------------ |
**ge_load_time**  | **20200727T171932.954810Z**
**pandas_data_fingerprint**  | **8c46fdaf0bd356fd58b7bcd9b2e6012d**
### Batch Kwargs
 |  |  |
 | ------------  | ------------ |
**PandasInMemoryDF**  | **True**
**datasource**  | **getest**
**ge_batch_id**  | **56615f40-d02d-11ea-b6ea-acde48001122**
-----------------------------------------------------------
Powered by [Great Expectations](https://greatexpectations.io/)
# Validation Results
## Overview
### **Expectation Suite:** **basic.warning**
**Data asset:** **None**
**Status:**  **Failed**
### Statistics
 |  |  |
 | ------------  | ------------ |
Evaluated Expectations  | 11
Successful Expectations  | 9
Unsuccessful Expectations  | 2
Success Percent  | ≈81.82%
## Table-Level Expectations
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
❌  | Must have greater than or equal to **27000** and less than or equal to **33000** rows.  | 30
✅  | Must have exactly **3** columns.  | 3
✅  | Must have these columns in this order: **Team**, ** "Payroll (millions)"**, ** "Wins"**  | ['Team', ' "Payroll (millions)"', ' "Wins"']
##  "Payroll (millions)"
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | minimum value must be greater than or equal to **54.24** and less than or equal to **56.24**.  | 55.24
✅  | maximum value must be greater than or equal to **196.96** and less than or equal to **198.96**.  | 197.96
✅  | mean must be greater than or equal to **97.01899999999998** and less than or equal to **99.01899999999998**.  | ≈98.019
❌  | median must be greater than or equal to **84000.75** and less than or equal to **86000.75**.  | 85.75
✅  | quantiles must be within the following value ranges.
 | Quantile | Min Value | Max Value |
 | ------------  | ------------  | ------------ |
0.05  | 54.37  | 56.37
Q1  | 74.48  | 76.48
Median  | 82.31  | 84.31
Q3  | 116.62  | 118.62
0.95  | 173.54  | 175.54
  |
 | Quantile | Value |
 | ------------  | ------------ |
0.05  | 55.37
Q1  | 75.48
Median  | 83.31
Q3  | 117.62
0.95  | 174.54
## Team
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | values must always be greater than or equal to **1** characters long.  | 0% unexpected
### Info
 |  |  |
 | ------------  | ------------ |
Great Expectations Version  | 0.11.8+4.g4ab34df3.dirty
Run Name  | getest run
Run Time  | 2020-07-27T17:19:32Z
### Batch Markers
 |  |  |
 | ------------  | ------------ |
**ge_load_time**  | **20200727T171932.954810Z**
**pandas_data_fingerprint**  | **8c46fdaf0bd356fd58b7bcd9b2e6012d**
### Batch Kwargs
 |  |  |
 | ------------  | ------------ |
**PandasInMemoryDF**  | **True**
**datasource**  | **getest**
**ge_batch_id**  | **56615f40-d02d-11ea-b6ea-acde48001122**
-----------------------------------------------------------
Powered by [Great Expectations](https://greatexpectations.io/)
""".replace(
            " ", ""
        )
        .replace("\t", "")
        .replace("\n", "")
    )


def test_render_section_page_with_fixture_data_multiple_validations(
    validation_operator_result,
):
    """
    Make sure the appropriate markdown rendering is done for the applied fixture.
    :param validation_operator_result: test fixture
    :return: None
    """

    validation_operator_result = ValidationOperatorResult(**validation_operator_result)

    validation_results_page_renderer = ValidationResultsPageRenderer(
        run_info_at_end=True
    )

    rendered_document_content_list = (
        validation_results_page_renderer.render_validation_operator_result(
            validation_operator_result=validation_operator_result
        )
    )

    md_str_list = DefaultMarkdownPageView().render(rendered_document_content_list)

    md_str = " ".join(md_str_list)

    md_str = md_str.replace(" ", "").replace("\t", "").replace("\n", "")

    # print(md_str)

    assert (
        md_str
        == """
# Validation Results
## Overview
### **Expectation Suite:** **basic.warning**
**Dataasset:** **None**
**Status:**  **Failed**
### Statistics
 |  |  |
 | ------------  | ------------ |
Evaluated Expectations  | 11
Successful Expectations  | 9
Unsuccessful Expectations  | 2
Success Percent  | ≈81.82%
## Table-Level Expectations
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
❌  | Must have greater than or equal to **27000** and less than or equal to **33000** rows.  | 30
✅  | Must have exactly **3** columns.  | 3
✅  | Must have these columns in this order: **Team**, ** "Payroll (millions)"**, ** "Wins"**  | ['Team', ' "Payroll (millions)"', ' "Wins"']
##  "Payroll (millions)"
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | minimum value must be greater than or equal to **54.24** and less than or equal to **56.24**.  | 55.24
✅  | maximum value must be greater than or equal to **196.96** and less than or equal to **198.96**.  | 197.96
✅  | mean must be greater than or equal to **97.01899999999998** and less than or equal to **99.01899999999998**.  | ≈98.019
❌  | median must be greater than or equal to **84000.75** and less than or equal to **86000.75**.  | 85.75
✅  | quantiles must be within the following value ranges.
 | Quantile | Min Value | Max Value |
 | ------------  | ------------  | ------------ |
0.05  | 54.37  | 56.37
Q1  | 74.48  | 76.48
Median  | 82.31  | 84.31
Q3  | 116.62  | 118.62
0.95  | 173.54  | 175.54
  |
 | Quantile | Value |
 | ------------  | ------------ |
0.05  | 55.37
Q1  | 75.48
Median  | 83.31
Q3  | 117.62
0.95  | 174.54
## Team
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | values must always be greater than or equal to **1** characters long.  | 0% unexpected
### Info
 |  |  |
 | ------------  | ------------ |
Great Expectations Version  | 0.11.8+4.g4ab34df3.dirty
Run Name  | getest run
Run Time  | 2020-07-27T17:19:32Z
### Batch Markers
 |  |  |
 | ------------  | ------------ |
**ge_load_time**  | **20200727T171932.954810Z**
**pandas_data_fingerprint**  | **8c46fdaf0bd356fd58b7bcd9b2e6012d**
### Batch Kwargs
 |  |  |
 | ------------  | ------------ |
**PandasInMemoryDF**  | **True**
**datasource**  | **getest**
**ge_batch_id**  | **56615f40-d02d-11ea-b6ea-acde48001122**
-----------------------------------------------------------
Powered by [Great Expectations](https://greatexpectations.io/)
# Validation Results
## Overview
### **Expectation Suite:** **basic.warning**
**Dataasset:** **None**
**Status:**  **Failed**
### Statistics
 |  |  |
 | ------------  | ------------ |
Evaluated Expectations  | 11
Successful Expectations  | 9
Unsuccessful Expectations  | 2
Success Percent  | ≈81.82%
## Table-Level Expectations
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
❌  | Must have greater than or equal to **27000** and less than or equal to **33000** rows.  | 30
✅  | Must have exactly **3** columns.  | 3
✅  | Must have these columns in this order: **Team**, ** "Payroll (millions)"**, ** "Wins"**  | ['Team', ' "Payroll (millions)"', ' "Wins"']
##  "Payroll (millions)"
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | minimum value must be greater than or equal to **54.24** and less than or equal to **56.24**.  | 55.24
✅  | maximum value must be greater than or equal to **196.96** and less than or equal to **198.96**.  | 197.96
✅  | mean must be greater than or equal to **97.01899999999998** and less than or equal to **99.01899999999998**.  | ≈98.019
❌  | median must be greater than or equal to **84000.75** and less than or equal to **86000.75**.  | 85.75
✅  | quantiles must be within the following value ranges.
 | Quantile | Min Value | Max Value |
 | ------------  | ------------  | ------------ |
0.05  | 54.37  | 56.37
Q1  | 74.48  | 76.48
Median  | 82.31  | 84.31
Q3  | 116.62  | 118.62
0.95  | 173.54  | 175.54
  |
 | Quantile | Value |
 | ------------  | ------------ |
0.05  | 55.37
Q1  | 75.48
Median  | 83.31
Q3  | 117.62
0.95  | 174.54
## Team
 | Status | Expectation | Observed Value |
 | ------------  | ------------  | ------------ |
✅  | values must never be null.  | 100% not null
✅  | values must always be greater than or equal to **1** characters long.  | 0% unexpected
### Info
 |  |  |
 | ------------  | ------------ |
Great Expectations Version  | 0.11.8+4.g4ab34df3.dirty
Run Name  | getest run
Run Time  | 2020-07-27T17:19:32Z
### Batch Markers
 |  |  |
 | ------------  | ------------ |
**ge_load_time**  | **20200727T171932.954810Z**
**pandas_data_fingerprint**  | **8c46fdaf0bd356fd58b7bcd9b2e6012d**
### Batch Kwargs
 |  |  |
 | ------------  | ------------ |
**PandasInMemoryDF**  | **True**
**datasource**  | **getest**
**ge_batch_id**  | **56615f40-d02d-11ea-b6ea-acde48001122**
-----------------------------------------------------------
Powered by [Great Expectations](https://greatexpectations.io/)
""".replace(
            " ", ""
        )
        .replace("\t", "")
        .replace("\n", "")
    )


def test_render_expectation_suite_for_Markdown(expectation_suite_to_render_with_notes):
    expectation_suite_page_renderer = ExpectationSuitePageRenderer()
    rendered_document_content_list = expectation_suite_page_renderer.render(
        expectation_suite_to_render_with_notes
    )
    md_str = DefaultMarkdownPageView().render(rendered_document_content_list)
    md_str = " ".join(md_str)
    md_str = md_str.replace(" ", "").replace("\t", "").replace("\n", "")
    assert (
        md_str
        == r"""
   # Validation Results
## Overview
### Info
 |  |  |
 | ------------  | ------------ |
Expectation Suite Name  | default
Great Expectations Version  | 0.13.0-test
### Notes
    This Expectation suite currently contains 5 total Expectations across 5 columns.
## infinities
  * is a required field.
  * ***
## irrationals
  * distinct values must belong to this set: \* **1st** **2nd**.
  * ***
## naturals
  * is a required field.
  * ***
## nulls
  * is a required field.
  * ***
## testings
  * values must be unique.
    #### Notes:
      Example notes about this expectation. **Markdown** `Supported`.

      Second example note **with** *Markdown*
  * ***
-----------------------------------------------------------
Powered by [Great Expectations](https://greatexpectations.io/)
    """.replace(
            " ", ""
        )
        .replace("\t", "")
        .replace("\n", "")
    )
