import logging
from datetime import timedelta

from flask import Blueprint, Response, abort, redirect, url_for

from cubedash import _model, _utils, _utils as utils

_LOG = logging.getLogger(__name__)
bp = Blueprint("product", __name__)


@bp.route("/about.csv")
def legacy_about_csv():
    return redirect(".storage_csv")


@bp.route("/audit/storage.csv")
def storage_csv():
    """Get the product storage table as a CSV"""

    product_locations = _model.STORE.products_location_samples_all()
    return utils.as_csv(
        filename_prefix="product-information",
        headers=(
            "name",
            "count",
            "locations",
            "license",
            "definition",
            "summary_time",
            "metadata_type",
        ),
        rows=(
            (
                product.name,
                summary.dataset_count,
                [
                    location.common_prefix
                    for location in (product_locations.get(product.name) or [])
                ],
                _utils.product_license(product),
                url_for("product.raw_product_doc", name=product.name, _external=True),
                summary.last_refresh_time,
                product.metadata_type.name,
            )
            for product, summary in _model.get_products_with_summaries()
        ),
    )


@bp.route("/products.txt")
def product_list_text():
    # This is useful for bash scripts when we want to loop products :)
    return Response(
        "\n".join(t.name for t in _model.STORE.all_dataset_types()),
        content_type="text/plain",
    )


@bp.route("/metadata-types.txt")
def metadata_type_list_text():
    # This is useful for bash scripts when we want to loop them :)
    return Response(
        "\n".join(t.name for t in _model.STORE.all_metadata_types()),
        content_type="text/plain",
    )


@bp.route("/audit/storage")
def storage_page():
    product_locations = _model.STORE.products_location_samples_all()

    return utils.render(
        "storage.html",
        product_summary_and_location=[
            (product, summary, (product_locations.get(product.name) or []))
            for product, summary in _model.get_products_with_summaries()
        ],
    )


@bp.route("/product")
def product_redirect():
    """
    If people remove the name from a "/product/<name>" url, take them somewhere useful
    """
    return redirect(url_for(".products_page"))


@bp.route("/products")
def products_page():
    return utils.render(
        "products.html",
    )


@bp.route("/metadata-types")
def metadata_types_page():
    return utils.render(
        "metadata-types.html",
    )


@bp.route("/product/<name>.odc-product.yaml")
def legacy_raw_product_doc(name):
    return redirect(url_for(".raw_product_doc", name=name))


@bp.route("/products/<name>.odc-product.yaml")
def raw_product_doc(name):
    product = _model.STORE.index.products.get_by_name(name)
    if not product:
        abort(404, f"Unknown product {name!r}")

    ordered_metadata = utils.prepare_document_formatting(
        product.definition, "Product", include_source_url=True
    )
    return utils.as_yaml(ordered_metadata)


@bp.route("/metadata-type/<name>")
def legacy_metadata_type_page(name):
    return redirect(url_for(".metadata_type_page", name=name))


@bp.route("/metadata-types/<name>")
def metadata_type_page(name):
    metadata_type = _model.STORE.index.metadata_types.get_by_name(name)
    if not metadata_type:
        abort(404, f"Unknown metadata type {name!r}")
    ordered_metadata = utils.prepare_document_formatting(metadata_type.definition)

    products_using_it = sorted(
        (
            p
            for p in _model.STORE.index.products.get_all()
            if p.metadata_type.name == name
        ),
        key=lambda p: p.name,
    )
    return utils.render(
        "metadata-type.html",
        metadata_type=metadata_type,
        metadata_doc=ordered_metadata,
        products_using_it=products_using_it,
    )


@bp.route("/metadata-type/<name>.odc-type.yaml")
def legacy_metadata_type_doc(name):
    return redirect(url_for(".raw_metadata_type_doc", name=name))


@bp.route("/metadata-types/<name>.odc-type.yaml")
def raw_metadata_type_doc(name):
    metadata_type = _model.STORE.index.metadata_types.get_by_name(name)
    if not metadata_type:
        abort(404, f"Unknown metadata type {name!r}")
    ordered_metadata = utils.prepare_document_formatting(
        metadata_type.definition, "Metadata Type", include_source_url=True
    )
    return utils.as_yaml(ordered_metadata)


@bp.route("/products.odc-product.yaml")
def raw_all_products_doc():
    resp = utils.as_yaml(
        *(
            utils.prepare_document_formatting(
                product.definition,
                f"Product {product.name}",
                include_source_url=url_for(
                    ".raw_product_doc", name=product.name, _external=True
                ),
            )
            for product in _model.STORE.all_dataset_types()
        )
    )
    # Add Explorer ID to the download filename if they have one.
    utils.suggest_download_filename(
        resp,
        prefix="products",
        suffix=".odc-product.yaml",
    )

    return resp


@bp.route("/metadata-types.odc-type.yaml")
def raw_all_metadata_types_doc():
    resp = utils.as_yaml(
        *(
            utils.prepare_document_formatting(
                type_.definition,
                f"Metadata Type {type_.name}",
                include_source_url=url_for(
                    ".raw_metadata_type_doc", name=type_.name, _external=True
                ),
            )
            for type_ in _model.STORE.all_metadata_types()
        ),
    )
    # Add Explorer ID to the download filename if they have one.
    utils.suggest_download_filename(
        resp,
        prefix="metadata-types",
        suffix=".odc-type.yaml",
    )
    return resp


def _iso8601_duration(tdelta: timedelta):
    """
    Format a timedelta as an iso8601 duration

    >>> _iso8601_duration(timedelta(seconds=0))
    'PT0S'
    >>> _iso8601_duration(timedelta(seconds=1))
    'PT1S'
    >>> _iso8601_duration(timedelta(seconds=23423))
    'PT6H30M23S'
    >>> _iso8601_duration(timedelta(seconds=4564564556))
    'P52830DT14H35M56S'
    """
    all_secs = tdelta.total_seconds()

    secs = int(all_secs % 60)
    h_m_s = (
        int(all_secs // 3600 % 24),
        int(all_secs // 60 % 60),
        secs if secs % 1 != 0 else int(secs),
    )

    parts = ["P"]

    days = int(all_secs // 86400)
    if days:
        parts.append(f"{days}D")
    if any(h_m_s):
        parts.append("T")
    if all_secs:
        for val, name in zip(h_m_s, ["H", "M", "S"]):
            if val:
                parts.append(f"{val}{name}")
    else:
        parts.append("T0S")

    return "".join(parts)

[((173, 200), 'logging.getLogger', 'logging.getLogger', (['__name__'], {}), '(__name__)\n', (190, 200), False, 'import logging\n'), ((206, 236), 'flask.Blueprint', 'Blueprint', (['"""product"""', '__name__'], {}), "('product', __name__)\n", (215, 236), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((298, 322), 'flask.redirect', 'redirect', (['""".storage_csv"""'], {}), "('.storage_csv')\n", (306, 322), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((450, 494), 'cubedash._model.STORE.products_location_samples_all', '_model.STORE.products_location_samples_all', ([], {}), '()\n', (492, 494), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((1948, 1992), 'cubedash._model.STORE.products_location_samples_all', '_model.STORE.products_location_samples_all', ([], {}), '()\n', (1990, 1992), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((2503, 2532), 'cubedash._utils.render', 'utils.render', (['"""products.html"""'], {}), "('products.html')\n", (2515, 2532), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((2617, 2652), 'cubedash._utils.render', 'utils.render', (['"""metadata-types.html"""'], {}), "('metadata-types.html')\n", (2629, 2652), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((2900, 2945), 'cubedash._model.STORE.index.products.get_by_name', '_model.STORE.index.products.get_by_name', (['name'], {}), '(name)\n', (2939, 2945), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((3038, 3131), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', (['product.definition', '"""Product"""'], {'include_source_url': '(True)'}), "(product.definition, 'Product',\n    include_source_url=True)\n", (3071, 3131), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((3153, 3184), 'cubedash._utils.as_yaml', 'utils.as_yaml', (['ordered_metadata'], {}), '(ordered_metadata)\n', (3166, 3184), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((3410, 3461), 'cubedash._model.STORE.index.metadata_types.get_by_name', '_model.STORE.index.metadata_types.get_by_name', (['name'], {}), '(name)\n', (3455, 3461), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((3565, 3624), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', (['metadata_type.definition'], {}), '(metadata_type.definition)\n', (3598, 3624), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((3843, 3978), 'cubedash._utils.render', 'utils.render', (['"""metadata-type.html"""'], {'metadata_type': 'metadata_type', 'metadata_doc': 'ordered_metadata', 'products_using_it': 'products_using_it'}), "('metadata-type.html', metadata_type=metadata_type,\n    metadata_doc=ordered_metadata, products_using_it=products_using_it)\n", (3855, 3978), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((4272, 4323), 'cubedash._model.STORE.index.metadata_types.get_by_name', '_model.STORE.index.metadata_types.get_by_name', (['name'], {}), '(name)\n', (4317, 4323), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((4427, 4532), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', (['metadata_type.definition', '"""Metadata Type"""'], {'include_source_url': '(True)'}), "(metadata_type.definition, 'Metadata Type',\n    include_source_url=True)\n", (4460, 4532), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((4554, 4585), 'cubedash._utils.as_yaml', 'utils.as_yaml', (['ordered_metadata'], {}), '(ordered_metadata)\n', (4567, 4585), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((5115, 5204), 'cubedash._utils.suggest_download_filename', 'utils.suggest_download_filename', (['resp'], {'prefix': '"""products"""', 'suffix': '""".odc-product.yaml"""'}), "(resp, prefix='products', suffix=\n    '.odc-product.yaml')\n", (5146, 5204), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((5792, 5884), 'cubedash._utils.suggest_download_filename', 'utils.suggest_download_filename', (['resp'], {'prefix': '"""metadata-types"""', 'suffix': '""".odc-type.yaml"""'}), "(resp, prefix='metadata-types', suffix=\n    '.odc-type.yaml')\n", (5823, 5884), True, 'from cubedash import _model, _utils, _utils as utils\n'), ((2419, 2444), 'flask.url_for', 'url_for', (['""".products_page"""'], {}), "('.products_page')\n", (2426, 2444), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((2770, 2808), 'flask.url_for', 'url_for', (['""".raw_product_doc"""'], {'name': 'name'}), "('.raw_product_doc', name=name)\n", (2777, 2808), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((2974, 3013), 'flask.abort', 'abort', (['(404)', 'f"""Unknown product {name!r}"""'], {}), "(404, f'Unknown product {name!r}')\n", (2979, 3013), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((3279, 3320), 'flask.url_for', 'url_for', (['""".metadata_type_page"""'], {'name': 'name'}), "('.metadata_type_page', name=name)\n", (3286, 3320), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((3496, 3541), 'flask.abort', 'abort', (['(404)', 'f"""Unknown metadata type {name!r}"""'], {}), "(404, f'Unknown metadata type {name!r}')\n", (3501, 3541), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((4121, 4165), 'flask.url_for', 'url_for', (['""".raw_metadata_type_doc"""'], {'name': 'name'}), "('.raw_metadata_type_doc', name=name)\n", (4128, 4165), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((4358, 4403), 'flask.abort', 'abort', (['(404)', 'f"""Unknown metadata type {name!r}"""'], {}), "(404, f'Unknown metadata type {name!r}')\n", (4363, 4403), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((3703, 3740), 'cubedash._model.STORE.index.products.get_all', '_model.STORE.index.products.get_all', ([], {}), '()\n', (3738, 3740), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((1042, 1073), 'cubedash._utils.product_license', '_utils.product_license', (['product'], {}), '(product)\n', (1064, 1073), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((1091, 1160), 'flask.url_for', 'url_for', (['"""product.raw_product_doc"""'], {'name': 'product.name', '_external': '(True)'}), "('product.raw_product_doc', name=product.name, _external=True)\n", (1098, 1160), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((1299, 1335), 'cubedash._model.get_products_with_summaries', '_model.get_products_with_summaries', ([], {}), '()\n', (1333, 1335), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((1533, 1565), 'cubedash._model.STORE.all_dataset_types', '_model.STORE.all_dataset_types', ([], {}), '()\n', (1563, 1565), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((1797, 1830), 'cubedash._model.STORE.all_metadata_types', '_model.STORE.all_metadata_types', ([], {}), '()\n', (1828, 1830), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((2194, 2230), 'cubedash._model.get_products_with_summaries', '_model.get_products_with_summaries', ([], {}), '()\n', (2228, 2230), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((4997, 5029), 'cubedash._model.STORE.all_dataset_types', '_model.STORE.all_dataset_types', ([], {}), '()\n', (5027, 5029), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((5672, 5705), 'cubedash._model.STORE.all_metadata_types', '_model.STORE.all_metadata_types', ([], {}), '()\n', (5703, 5705), False, 'from cubedash import _model, _utils, _utils as utils\n'), ((4854, 4916), 'flask.url_for', 'url_for', (['""".raw_product_doc"""'], {'name': 'product.name', '_external': '(True)'}), "('.raw_product_doc', name=product.name, _external=True)\n", (4861, 4916), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((5527, 5593), 'flask.url_for', 'url_for', (['""".raw_metadata_type_doc"""'], {'name': 'type_.name', '_external': '(True)'}), "('.raw_metadata_type_doc', name=type_.name, _external=True)\n", (5534, 5593), False, 'from flask import Blueprint, Response, abort, redirect, url_for\n')]