import os
import fiona
import fiona.ogrext
import logging
from random import uniform, randint
from collections import defaultdict
import pytest

has_gpkg = "GPKG" in fiona.supported_drivers.keys()

def create_records(count):
    for n in range(count):
        record = {
            "geometry": {"type": "Point", "coordinates": [uniform(-180, 180), uniform(-90, 90)]},
            "properties": {"value": randint(0, 1000)}
        }
        yield record

class DebugHandler(logging.Handler):
    def __init__(self, pattern):
        logging.Handler.__init__(self)
        self.pattern = pattern
        self.history = defaultdict(lambda: 0)

    def emit(self, record):
        if self.pattern in record.msg:
            self.history[record.msg] += 1


log = logging.getLogger()


@pytest.mark.skipif(not has_gpkg, reason="Requires geopackage driver")
class TestTransaction:
    def setup_method(self):
        self.handler = DebugHandler(pattern="transaction")
        self.handler.setLevel(logging.DEBUG)
        log.setLevel(logging.DEBUG)
        log.addHandler(self.handler)

    def teardown_method(self):
        log.removeHandler(self.handler)

    def test_transaction(self, tmpdir):
        """
        Test transaction start/commit is called the expected number of times,
        and that the default transaction size can be overloaded. The test uses
        a custom logging handler to listen for the debug messages produced
        when the transaction is started/comitted.
        """
        num_records = 250
        transaction_size = 100

        assert fiona.ogrext.DEFAULT_TRANSACTION_SIZE == 20000
        fiona.ogrext.DEFAULT_TRANSACTION_SIZE = transaction_size
        assert fiona.ogrext.DEFAULT_TRANSACTION_SIZE == transaction_size

        path = str(tmpdir.join("output.gpkg"))

        schema = {
            "geometry": "Point",
            "properties": {"value": "int"}
        }

        with fiona.open(path, "w", driver="GPKG", schema=schema) as dst:
            dst.writerecords(create_records(num_records))

        assert self.handler.history["Starting transaction (initial)"] == 1
        assert self.handler.history["Starting transaction (intermediate)"] == num_records // transaction_size
        assert self.handler.history["Comitting transaction (intermediate)"] == num_records // transaction_size
        assert self.handler.history["Comitting transaction (final)"] == 1

        with fiona.open(path, "r") as src:
            assert len(src) == num_records
