import itertools
import logging
import os
import sys
from contextlib import closing

import flask
from flask import render_template
from flask import request
from packaging.version import parse
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()


class PluginResult(Base):
    """Results of testing a pytest plugin against a pytest and python version."""

    __tablename__ = "results"

    id = Column(Integer, primary_key=True)
    name = Column(String, index=True)
    version = Column(String, index=True)
    env = Column(String)
    pytest = Column(String)
    status = Column(String)
    output = Column(String)
    description = Column(String, default="")

    def as_dict(self):
        return {
            "name": self.name,
            "version": self.version,
            "env": self.env,
            "pytest": self.pytest,
            "status": self.status,
            "output": self.output,
            "description": self.description,
        }

    def __repr__(self):
        attrs = [f"{k}={v!r}" for k, v in self.as_dict().items()]
        return f"PluginResult({', '.join(attrs)})"

    def __eq__(self, other):
        if not isinstance(other, PluginResult):
            return NotImplemented
        return self.as_dict() == other.as_dict()


app = flask.Flask("plugincompat")


def get_python_versions():
    """
    Python versions we are willing to display on the page, in order to ignore
    old and incomplete results.
    """
    return {"py36", "py37", "py38"}


def get_pytest_versions():
    """
    Same as `get_python_versions`, but for pytest versions.
    """
    return {"6.0.1"}


class PlugsStorage:
    """
    API around a MongoDatabase used to add and obtain test results for pytest plugins.
    """

    def __init__(self, url=None):
        url = url or os.environ["DATABASE_URL"]
        self._engine = create_engine(url)
        Base.metadata.create_all(self._engine)
        self._session_maker = sessionmaker(autocommit=False, autoflush=False, bind=self._engine)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self._engine.dispose()

    def add_test_result(self, payload):