from datetime import datetime, timedelta

import numpy as np
import pytest

import astrodata
from astrodata import fits
from astrodata.provenance import (add_provenance,
                                  add_provenance_history, clone_provenance,
                                  clone_provenance_history)


@pytest.fixture
def ad():
    phu = fits.PrimaryHDU()
    hdu = fits.ImageHDU(data=np.ones((10, 10)), name='SCI')
    return astrodata.create(phu, [hdu])


@pytest.fixture
def ad2():
    phu = fits.PrimaryHDU()
    hdu = fits.ImageHDU(data=np.ones((10, 10)), name='SCI')
    return astrodata.create(phu, [hdu])


def test_add_get_provenance(ad):
    timestamp = datetime.utcnow().isoformat()
    filename = "filename"
    md5 = "md5"
    primitive = "provenance_added_by"

    # if md5 is None, nothing is added
    add_provenance(ad, filename, None, primitive)
    assert not hasattr(ad, 'PROVENANCE')

    add_provenance(ad, filename, md5, primitive, timestamp=timestamp)
    assert len(ad.PROVENANCE) == 1
    assert tuple(ad.PROVENANCE[0]) == (timestamp, filename, md5, primitive)

    # entry is updated and a default timestamp is created
    add_provenance(ad, filename, md5, primitive)
    assert len(ad.PROVENANCE) == 1
    assert tuple(ad.PROVENANCE[0])[1:] == (filename, md5, primitive)

    # add new entry
    add_provenance(ad, filename, 'md6', 'other primitive')
    assert len(ad.PROVENANCE) == 2
    assert tuple(ad.PROVENANCE[0])[1:] == (filename, md5, primitive)
    assert tuple(ad.PROVENANCE[1])[1:] == (filename, 'md6', 'other primitive')


def test_add_duplicate_provenance(ad):
    timestamp = datetime.utcnow().isoformat()
    filename = "filename"
    md5 = "md5"
    primitive = "provenance_added_by"

    add_provenance(ad, filename, md5, primitive, timestamp=timestamp)
    add_provenance(ad, filename, md5, primitive, timestamp=timestamp)

    # was a dupe, so should have been skipped
    assert len(ad.PROVENANCE) == 1


def test_add_get_provenance_history(ad):
    timestamp_start = datetime.utcnow()
    timestamp_end = (timestamp_start +
                     timedelta(days=1)).isoformat()
    timestamp_start = timestamp_start.isoformat()
    primitive = "primitive"
    args = "args"

    add_provenance_history(ad, timestamp_start, timestamp_end, primitive, args)
    assert len(ad.PROVHISTORY) == 1
    assert tuple(ad.PROVHISTORY[0]) == (primitive, args, timestamp_start, timestamp_end)

    add_provenance_history(ad, timestamp_start, timestamp_end,
                           'another primitive', args)
    assert len(ad.PROVHISTORY) == 2
    assert tuple(ad.PROVHISTORY[0]) == (primitive, args, timestamp_start, timestamp_end)
    assert tuple(ad.PROVHISTORY[1]) == ('another primitive', args, timestamp_start, timestamp_end)


def test_add_dupe_provenance_history(ad):
    timestamp_start = datetime.utcnow()
    timestamp_end = (timestamp_start +
                     timedelta(days=1)).isoformat()
    timestamp_start = timestamp_start.isoformat()
    primitive = "primitive"
    args = "args"

    add_provenance_history(ad, timestamp_start, timestamp_end, primitive, args)
    add_provenance_history(ad, timestamp_start, timestamp_end, primitive, args)

    # was a dupe, should have skipped 2nd add
    assert len(ad.PROVHISTORY) == 1


def test_clone_provenance(ad, ad2):
    timestamp = datetime.utcnow().isoformat()
    filename = "filename"
    md5 = "md5"
    primitive = "provenance_added_by"

    add_provenance(ad, filename, md5, primitive, timestamp=timestamp)

    clone_provenance(ad.PROVENANCE, ad2)

    assert len(ad2.PROVENANCE) == 1
    assert tuple(ad2.PROVENANCE[0]) == (timestamp, filename, md5, primitive)


def test_clone_provenance_history(ad, ad2):
    timestamp_start = datetime.utcnow()
    timestamp_end = (timestamp_start +
                     timedelta(days=1)).isoformat()
    timestamp_start = timestamp_start.isoformat()
    primitive = "primitive"
    args = "args"

    add_provenance_history(ad, timestamp_start, timestamp_end, primitive, args)

    clone_provenance_history(ad.PROVHISTORY, ad2)

    assert len(ad2.PROVHISTORY) == 1
    assert tuple(ad2.PROVHISTORY[0]) == (primitive, args, timestamp_start, timestamp_end)
