import cPickle
import datetime
import json
import sys
import shutil
import time

import pytest

from quixote import cleanup
from wcs import formdef
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.workflows import Workflow
from wcs.fields import StringField, FileField, DateField, ItemField

from utilities import create_temporary_pub, clean_temporary_pub

def pytest_generate_tests(metafunc):
    if 'pub' in metafunc.fixturenames:
        metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)

@pytest.fixture
def pub(request):
    pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
    req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
    pub.set_app_dir(req)
    pub.cfg['language'] = {'language': 'en'}
    pub.write_cfg()

    return pub

def teardown_module(module):
    clean_temporary_pub()


def test_is_disabled(pub):
    formdef = FormDef()
    assert not formdef.is_disabled()

    formdef.disabled = True
    assert formdef.is_disabled()


def test_is_disabled_publication_date(pub):
    formdef = FormDef()

    formdef.publication_date = '%s-%02d-%02d' % (datetime.datetime.today() - datetime.timedelta(1)).timetuple()[:3]
    assert not formdef.is_disabled()

    formdef.publication_date = '%s-%02d-%02d' % (datetime.datetime.today() + datetime.timedelta(1)).timetuple()[:3]
    assert formdef.is_disabled()


def test_is_disabled_expiration_date(pub):
    formdef = FormDef()

    formdef.expiration_date = '%s-%02d-%02d' % (datetime.datetime.today() - datetime.timedelta(1)).timetuple()[:3]
    assert formdef.is_disabled()

    formdef.expiration_date = '%s-%02d-%02d' % (datetime.datetime.today() + datetime.timedelta(1)).timetuple()[:3]
    assert not formdef.is_disabled()


def test_is_disabled_publication_datetime(pub):
    formdef = FormDef()

    formdef.publication_date = '%s-%02d-%02d %02d:%02d' % (
            datetime.datetime.now() - datetime.timedelta(hours=1)).timetuple()[:5]
    assert not formdef.is_disabled()

    formdef.publication_date = '%s-%02d-%02d %02d:%02d' % (
            datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5]
    assert formdef.is_disabled()


def test_is_disabled_expiration_datetime(pub):
    formdef = FormDef()

    formdef.expiration_date = '%s-%02d-%02d %02d:%02d' % (
            datetime.datetime.now() - datetime.timedelta(hours=1)).timetuple()[:5]
    assert formdef.is_disabled()

    formdef.expiration_date = '%s-%02d-%02d %02d:%02d' % (
            datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5]
    assert not formdef.is_disabled()

def test_title_change(pub):
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.store()
    assert FormDef.get(formdef.id).name == 'foo'
    assert FormDef.get(formdef.id).url_name == 'foo'
    assert FormDef.get(formdef.id).internal_identifier == 'foo'

    formdef.name = 'bar'
    formdef.store()
    assert FormDef.get(formdef.id).name == 'bar'
    assert FormDef.get(formdef.id).url_name == 'foo'
    assert FormDef.get(formdef.id).internal_identifier == 'bar'

    # makes sure the internal_name doesn't change if there are submitted forms
    formdef.data_class()().store()
    formdef.name = 'baz'
    formdef.store()
    assert FormDef.get(formdef.id).name == 'baz'
    assert FormDef.get(formdef.id).internal_identifier == 'bar' # didn't change

def test_substitution_variables(pub):
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.store()

    from wcs.workflows import WorkflowVariablesFieldsFormDef
    wf = Workflow(name='variables')
    wf.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=wf)
    wf.variables_formdef.fields = [
        StringField(id='1', label='Test', type='string', varname='foo'),
        ItemField(id='2', label='Test Liste', type='item', varname='bar'),
    ]
    wf.store()
    formdef.workflow_id = wf.id

    assert 'form_name' in formdef.get_substitution_variables()
    assert formdef.get_substitution_variables()['form_name'] == 'foo'
    formdef.workflow_options = {'foo': 'bar'}
    assert 'form_option_foo' in formdef.get_substitution_variables()
    assert formdef.get_substitution_variables()['form_option_foo'] == 'bar'

    formdef.workflow_options = {'bar': 'bar', 'bar_display': 'Bar'}
    assert formdef.get_substitution_variables()['form_option_bar'] == 'Bar'
    assert formdef.get_substitution_variables()['form_option_bar_raw'] == 'bar'

def test_schema_with_date_variable(pub):
    FormDef.wipe()
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.store()

    from wcs.workflows import WorkflowVariablesFieldsFormDef
    wf = Workflow(name='variables')
    wf.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=wf)
    wf.variables_formdef.fields.append(
            DateField(label='Test', type='date', varname='foo'))
    wf.store()
    formdef.workflow_id = wf.id
    formdef.workflow_options = {'foo':  time.gmtime(time.mktime((2016, 4, 2, 0, 0, 0, 0, 0, 0)))}
    assert json.loads(formdef.export_to_json())['options']['foo'].startswith('2016-04')

def test_substitution_variables_object(pub):
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.store()
    formdef.data_class().wipe()

    assert 'form_objects' in formdef.get_substitution_variables()
    substs = formdef.get_substitution_variables().get('form_objects')
    assert substs.count == 0
    assert substs.count_status_1 == 0

    d = formdef.data_class()()
    d.status = 'wf-1'
    d.store()
    assert substs.count == 1
    assert substs.count_status_1 == 1

    with pytest.raises(AttributeError):
        assert substs.foobar

def test_file_field_migration(pub):
    pub.cfg['filetypes'] = {1:
            {'mimetypes': [
                'application/pdf',
                'application/vnd.oasis.opendocument.text',
                'application/msword',
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                'application/vnd.oasis.opendocument.spreadsheet',
                'application/vnd.ms-excel',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
             'label': 'Documents'}}

    FormDef.wipe()
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.fields = [
            FileField(type='file', id='1', label='images & docs'),
            FileField(type='file', id='2', label='images')]
    formdef.fields[0].__dict__['file_type'] = ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
    formdef.fields[1].__dict__['file_type'] = ['image/*']
    formdef.store()
    formdef = FormDef.get(1)
    assert 'file_type' not in formdef.fields[0].__dict__
    assert formdef.fields[0].document_type
    assert formdef.fields[0].document_type['id'] == '_legacy'
    assert formdef.fields[0].document_type['mimetypes'] == ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
    assert formdef.fields[1].document_type['label'] == 'Image files'
    assert formdef.fields[0].document_type['label'] == 'Image files, Documents'

def test_internal_identifier_migration(pub):
    FormDef.wipe()
    formdef = FormDef()
    formdef.name = 'foo'
    formdef.fields = []
    formdef.store()

    obj = cPickle.load(open(formdef.get_object_filename()))
    del obj.internal_identifier
    cPickle.dump(obj, open(formdef.get_object_filename(), 'w'))
    assert cPickle.load(open(formdef.get_object_filename())).internal_identifier is None
    assert FormDef.get(formdef.id, ignore_migration=True).internal_identifier is None

    formdef = FormDef.get(formdef.id)
    assert formdef.internal_identifier == 'foo'
