from typing import Optional

from arti.fingerprints import Fingerprint
from arti.partitions import CompositeKey
from arti.storage import InputFingerprints, Storage, StoragePartition

_not_written_err = FileNotFoundError("Literal has not been written yet")


class StringLiteralPartition(StoragePartition):
    id: str
    value: Optional[str]

    def compute_content_fingerprint(self) -> Fingerprint:
        if self.value is None:
            raise _not_written_err
        return Fingerprint.from_string(self.value)


class StringLiteral(Storage[StringLiteralPartition]):
    """StringLiteral stores a literal String value directly in the Backend."""

    id: str = "{graph_name}/{path_tags}/{names}/{partition_key_spec}/{input_fingerprint}/{name}{extension}"
    value: Optional[str]

    def discover_partitions(
        self, input_fingerprints: InputFingerprints = InputFingerprints()
    ) -> tuple[StringLiteralPartition, ...]:
        if input_fingerprints and self.value is not None:
            raise ValueError(
                f"Literal storage cannot have a `value` preset ({self.value}) for a Producer output"
            )
        if self.key_types and not input_fingerprints:
            # We won't know what partitions to lookup.
            raise ValueError("Literal storage can only be partitioned if generated by a Producer.")
        # Existing StringLiteralPartitions may be stored in the Graph's backend, however we don't
        # have access here to lookup.
        if self.value is None:
            return ()
        return tuple(
            self.generate_partition(input_fingerprint=input_fingerprint, keys=keys)
            for keys, input_fingerprint in (
                input_fingerprints or {CompositeKey(): Fingerprint.empty()}
            ).items()
        )
