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)

[((8, 7, 8, 34), 'logging.getLogger', 'logging.getLogger', ({(8, 25, 8, 33): '__name__'}, {}), '(__name__)', False, 'import logging\n'), ((9, 5, 9, 35), 'flask.Blueprint', 'Blueprint', ({(9, 15, 9, 24): '"""product"""', (9, 26, 9, 34): '__name__'}, {}), "('product', __name__)", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((14, 11, 14, 35), 'flask.redirect', 'redirect', ({(14, 20, 14, 34): '""".storage_csv"""'}, {}), "('.storage_csv')", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((21, 24, 21, 68), 'cubedash._model.STORE.products_location_samples_all', '_model.STORE.products_location_samples_all', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((71, 24, 71, 68), 'cubedash._model.STORE.products_location_samples_all', '_model.STORE.products_location_samples_all', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((92, 11, 94, 5), 'cubedash._utils.render', 'utils.render', ({(93, 8, 93, 23): '"""products.html"""'}, {}), "('products.html')", True, 'from cubedash import _model, _utils, _utils as utils\n'), ((99, 11, 101, 5), 'cubedash._utils.render', 'utils.render', ({(100, 8, 100, 29): '"""metadata-types.html"""'}, {}), "('metadata-types.html')", True, 'from cubedash import _model, _utils, _utils as utils\n'), ((111, 14, 111, 59), 'cubedash._model.STORE.index.products.get_by_name', '_model.STORE.index.products.get_by_name', ({(111, 54, 111, 58): 'name'}, {}), '(name)', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((115, 23, 117, 5), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', (), '', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((118, 11, 118, 42), 'cubedash._utils.as_yaml', 'utils.as_yaml', ({(118, 25, 118, 41): 'ordered_metadata'}, {}), '(ordered_metadata)', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((128, 20, 128, 71), 'cubedash._model.STORE.index.metadata_types.get_by_name', '_model.STORE.index.metadata_types.get_by_name', ({(128, 66, 128, 70): 'name'}, {}), '(name)', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((131, 23, 131, 82), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', ({(131, 57, 131, 81): 'metadata_type.definition'}, {}), '(metadata_type.definition)', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((141, 11, 146, 5), 'cubedash._utils.render', 'utils.render', (), '', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((156, 20, 156, 71), 'cubedash._model.STORE.index.metadata_types.get_by_name', '_model.STORE.index.metadata_types.get_by_name', ({(156, 66, 156, 70): 'name'}, {}), '(name)', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((159, 23, 161, 5), 'cubedash._utils.prepare_document_formatting', 'utils.prepare_document_formatting', (), '', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((162, 11, 162, 42), 'cubedash._utils.as_yaml', 'utils.as_yaml', ({(162, 25, 162, 41): 'ordered_metadata'}, {}), '(ordered_metadata)', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((180, 4, 184, 5), 'cubedash._utils.suggest_download_filename', 'utils.suggest_download_filename', (), '', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((204, 4, 208, 5), 'cubedash._utils.suggest_download_filename', 'utils.suggest_download_filename', (), '', True, 'from cubedash import _model, _utils, _utils as utils\n'), ((87, 20, 87, 45), 'flask.url_for', 'url_for', ({(87, 28, 87, 44): '""".products_page"""'}, {}), "('.products_page')", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((106, 20, 106, 58), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((113, 8, 113, 47), 'flask.abort', 'abort', ({(113, 14, 113, 17): '(404)', (113, 19, 113, 46): 'f"""Unknown product {name!r}"""'}, {}), "(404, f'Unknown product {name!r}')", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((123, 20, 123, 61), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((130, 8, 130, 53), 'flask.abort', 'abort', ({(130, 14, 130, 17): '(404)', (130, 19, 130, 52): 'f"""Unknown metadata type {name!r}"""'}, {}), "(404, f'Unknown metadata type {name!r}')", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((151, 20, 151, 64), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((158, 8, 158, 53), 'flask.abort', 'abort', ({(158, 14, 158, 17): '(404)', (158, 19, 158, 52): 'f"""Unknown metadata type {name!r}"""'}, {}), "(404, f'Unknown metadata type {name!r}')", False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((136, 21, 136, 58), 'cubedash._model.STORE.index.products.get_all', '_model.STORE.index.products.get_all', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((41, 16, 41, 47), 'cubedash._utils.product_license', '_utils.product_license', ({(41, 39, 41, 46): 'product'}, {}), '(product)', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((42, 16, 42, 85), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((46, 36, 46, 72), 'cubedash._model.get_products_with_summaries', '_model.get_products_with_summaries', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((55, 34, 55, 66), 'cubedash._model.STORE.all_dataset_types', '_model.STORE.all_dataset_types', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((64, 34, 64, 67), 'cubedash._model.STORE.all_metadata_types', '_model.STORE.all_metadata_types', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((77, 36, 77, 72), 'cubedash._model.get_products_with_summaries', '_model.get_products_with_summaries', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((176, 27, 176, 59), 'cubedash._model.STORE.all_dataset_types', '_model.STORE.all_dataset_types', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((200, 25, 200, 58), 'cubedash._model.STORE.all_metadata_types', '_model.STORE.all_metadata_types', ({}, {}), '()', False, 'from cubedash import _model, _utils, _utils as utils\n'), ((172, 35, 174, 17), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n'), ((196, 35, 198, 17), 'flask.url_for', 'url_for', (), '', False, 'from flask import Blueprint, Response, abort, redirect, url_for\n')]