from datetime import datetime
from glob import iglob
import logging
import os
from tempfile import NamedTemporaryFile
from typing import Optional, Tuple

from PIL import Image, ImageDraw, ImageFont
import tator
from tator.openapi.tator_openapi import CreateResponse, TatorApi

from hms_import.util import VESSEL_NAME_MAP, build_section_name, section_from_tus


logger = logging.getLogger(__name__)
FONT = os.path.join(os.path.dirname(__file__), "Cascadia.ttf")
FONT_SIZE = 36
SUMMARY_IMG_SZ = 1024


def create_summary_image(
    tator_api: TatorApi,
    media_type: int,
    directory: str,
    import_type: str,
    skip_decrypt: Optional[bool] = False,
    hdd_sn: Optional[str] = None,
) -> Tuple[Optional[int], str, str]:
    """Creates a summary image for a trip.

    :tator_api: The TatorApi object to use for interactions with Tator
    :media_type: The Tator media type to create
    :directory: The directory containing files to use to determine the vessel name
    :skip_decrypt: If true, use the decrypted filename format to find the vessel name
    :hdd_sn: The value for the HDD Serial Number attribute
    :returns: The created image id, section name, and found vessel name
    """

    vessel_name = "UNKNOWN"
    if import_type == "O2":
        # Get the vessel name and trip id from the first filename found starting with `stream-`
        if skip_decrypt:
            filename = os.path.basename(next(iglob(os.path.join(directory, f"*.mp4"))))
            name_parts = os.path.splitext(filename)[0].split("-")
            vessel_name = name_parts[0]
        else:
            filename = os.path.basename(next(iglob(os.path.join(directory, f"stream-*"))))
            name_parts = os.path.splitext(filename)[0].split("-")
            vessel_name = name_parts[1]
    elif import_type == "B3":
        video_list = list(iglob(os.path.join(directory, f"*.mp4")))
        video_path = video_list[0]
        filename = os.path.basename(video_path)
        filename_parts = os.path.splitext(filename)[0].split("-")
        if len(filename_parts) == 4:
            try:
                vessel_name = filename_parts[0]
            except Exception:
                logger.warning("Could not get the vessel or section name", exc_info=True)
    else:
        raise RuntimeError(f"Received unexepected import type argument: {import_type}")

    vessel_name = VESSEL_NAME_MAP.get(vessel_name, vessel_name)
    attrs = {"Vessel Name": vessel_name}
    attrs = {
        "Vessel Name": vessel_name,
        "HDD Date Received": datetime.fromisoformat(
            datetime.today().strftime("%Y-%m-%d")
        ).isoformat(),
        "HDD Serial Number": hdd_sn,
    }

    # Check for the existence of an image with the same attributes and return that if found
    project_id = tator_api.get_media_type(media_type).project
    paginator = tator.util.get_paginator(tator_api, "get_media_list")
    page_iter = paginator.paginate(project=project_id, type=media_type)
    try:
        for page in page_iter:
            for media in page:
                attributes = getattr(media, "attributes", {})
                match = True
                for key in ["Vessel Name", "HDD Date Received", "HDD Serial Number"]:
                    if attributes.get(key, None) != attrs[key]:
                        match = False
                        break
                if match:
                    logger.info("Found existing summary image %d", media.id)
                    section = section_from_tus(
                        tator_api, project_id, media.attributes["tator_user_sections"]
                    )
                    if section:
                        section_name = section.name
                    else:
                        section_name = build_section_name(vessel_name)
                    return media.id, section_name, vessel_name
    except (RuntimeError, StopIteration):
        # Bug in paginator will raise RuntimeError if zero entities are returned
        pass

    section_name = build_section_name(vessel_name)
    label_len = max(len(key) for key in attrs.keys())
    image_text = "\n".join(f"{k: >{label_len}}: {v}" for k, v in attrs.items())
    font = ImageFont.truetype(font=FONT, size=FONT_SIZE)
    image = Image.new("RGB", (SUMMARY_IMG_SZ, SUMMARY_IMG_SZ), color="black")
    draw = ImageDraw.Draw(image)
    left, top, right, bottom = draw.textbbox((0, 0), image_text, font=font)
    x_pos = (SUMMARY_IMG_SZ - (right - left)) // 2
    y_pos = (SUMMARY_IMG_SZ - (bottom - top)) // 2
    draw.text((x_pos, y_pos), image_text, fill="white", font=font)

    with NamedTemporaryFile(suffix=".png") as temp_file:
        image.save(temp_file.name)

        import_media_args = {
            "api": tator_api,
            "type_id": media_type,
            "path": temp_file.name,
            "section": section_name,
            "fname": os.path.basename(temp_file.name),
            "attributes": {k: v for k, v in attrs.items() if v is not None},
        }

        response = None
        summary_id = None
        try:
            for progress, response in tator.util.upload_media(**import_media_args):
                logger.info("Upload progress for %s: %d%%", temp_file.name, progress)
        except Exception:
            logger.error(
                "Could not create trip summary with args:\n%s", import_media_args, exc_info=True
            )
        else:
            if isinstance(response, CreateResponse):
                logger.info("Uploaded image, received response: %s", response.message)
                summary_id = response.id

    return summary_id, section_name, vessel_name
