import collections
import heapq
import json

from django.core.management.base import CommandError
from django.core.management.commands.loaddata import Command as FixtureFinder

from .rudiments import identity


class FixtureAccumulator:
    """
    Keeps record of fixtures in order of priority.

    >>> p = FixtureAccumulator()
    >>> p.add("harrie", "harrie/joekie")
    >>> p.add("catalogue", "catalogue/i18nproduct", 2)
    >>> p.add("harrie", "harrie/jantje", 7)
    >>> p.add("catalogue", "catalogue/product")
    >>> p.add("harrie", "harrie/jakkie", 1)
    >>> p
    <DefaultFixtureDict {
      "harrie": [
        [
          0,
          "harrie/joekie"
        ],
        [
          7,
          "harrie/jantje"
        ],
        [
          1,
          "harrie/jakkie"
        ]
      ],
      "catalogue": [
        [
          0,
          "catalogue/product"
        ],
        [
          2,
          "catalogue/i18nproduct"
        ]
      ]
    }>
    >>> list(p)
    ['harrie/jantje', 'catalogue/i18nproduct']
    >>> p.keys()
    dict_keys(['harrie', 'catalogue'])
    >>> list(p.items())
    [('harrie', 'harrie/jantje'), ('catalogue', 'catalogue/i18nproduct')]
    """

    def __init__(self):
        self.storage = collections.defaultdict(list)

    def __repr__(self):
        return "<DefaultFixtureDict %s>" % json.dumps(self.storage, indent=2)

    def add(self, key, fixture_path, priority=0):
        heapq.heappush(self.storage[key], (priority, fixture_path))

    def keys(self):
        return self.storage.keys()

    def items(self):
        for key, fixtures in self.storage.items():
            (fixture,) = heapq.nlargest(1, fixtures)
            yield (key, fixture[1])

    def __iter__(self):
        for _, fixtures in self.storage.items():
            (fixture,) = heapq.nlargest(1, fixtures)
            yield fixture[1]


def find_fixture(fixture_name):
    """
    Finds a fixture and returns the path.
    Also works with strange fixtures that can not be loaded at all like
    "original_images.tar.gz" or "books.essential.csv"
    """

    class Liar(collections.defaultdict):
        def __contains__(self, name):
            return True

    fixture_finder = FixtureFinder()
    fixture_finder.verbosity = 0
    fixture_finder.using = None
    fixture_finder.app_label = None
    fixture_finder.serialization_formats = Liar(lambda: True)
    fixture_finder.compression_formats = Liar(lambda: identity)

    try:
        for path, _, _ in fixture_finder.find_fixtures(fixture_name):
            return path
    except CommandError:
        return None
