import logging
import sys

import ocdskit.packager
from ocdskit.combine import merge
from ocdskit.commands.base import OCDSCommand
from ocdskit.exceptions import (
    CommandError,
    InconsistentVersionError,
    MissingOcidKeyError,
    NonObjectReleaseError,
    UnknownVersionError,
)

logger = logging.getLogger("ocdskit")


class Command(OCDSCommand):
    name = "compile"
    help = (
        "reads release packages and individual releases from standard input, merges the releases by OCID, "
        "and prints the compiled releases"
    )

    def add_arguments(self):
        self.add_argument("--schema", help="the URL or path of the patched release schema to use")
        self.add_argument("--package", action="store_true", help="wrap the compiled releases in a record package")
        self.add_argument(
            "--linked-releases",
            action="store_true",
            help="if --package is set, use linked releases instead of full releases",
        )
        self.add_argument(
            "--versioned",
            action="store_true",
            help="if --package is set, include versioned releases in the record package; otherwise, "
            "print versioned releases instead of compiled releases",
        )

        self.add_package_arguments("record", "if --package is set, ")

    def handle(self):
        kwargs = self.parse_package_arguments()
        kwargs["schema"] = self.args.schema
        kwargs["return_package"] = self.args.package
        kwargs["use_linked_releases"] = self.args.linked_releases
        kwargs["return_versioned_release"] = self.args.versioned

        if not ocdskit.packager.USING_SQLITE:
            logger.warning(
                "sqlite3 is unavailable, so the command will run in memory. If input files are too large, "
                "the command might exceed available memory."
            )

        try:
            for output in merge(self.items(), streaming=True, **kwargs):
                self.print(output, streaming=self.args.package)
        except MissingOcidKeyError as e:
            raise CommandError("The `ocid` field of at least one release is missing.") from e
        except NonObjectReleaseError as e:
            raise CommandError(f"At least one release is a {e}, not a dict.") from e
        except UnknownVersionError as e:
            raise CommandError(f'The `version` value ("{e}") of a release package is not recognized.') from e
        except InconsistentVersionError as e:
            versions = [e.earlier_version, e.current_version]
            if versions[1] < versions[0]:
                versions.reverse()

            raise CommandError(
                f"{e}\nTry first upgrading items to the same version:\n  cat file [file ...] | ocdskit upgrade "
                f"{versions[0]}:{versions[1]} | ocdskit {' '.join(sys.argv[1:])}"
            ) from e
