# -*- coding: utf-8 -
import os
import random
import hashlib
from datetime import timedelta
from tempfile import NamedTemporaryFile
from uuid import uuid4
from faker import Factory
from faker.providers.company.en_US import Provider as CompanyProviderEnUs
from faker.providers.company.ru_RU import Provider as CompanyProviderRuRu
from munch import munchify
from op_faker import OP_Provider
from .local_time import get_now, TZ

fake_en = Factory.create(locale='en_US')
fake_ru = Factory.create(locale='ru_RU')
fake_uk = Factory.create(locale='uk_UA')
fake_uk.add_provider(OP_Provider)
fake = fake_uk
used_identifier_id = []
mode_open = ["belowThreshold", "aboveThresholdUA", "aboveThresholdEU",
             "aboveThresholdUA.defense", "competitiveDialogueUA", "competitiveDialogueEU", "esco",
             "closeFrameworkAgreementUA"]
mode_limited = ["reporting", "negotiation.quick", "negotiation"]
violationType = ["corruptionDescription", "corruptionProcurementMethodType", "corruptionChanges",
                 "corruptionPublicDisclosure", "corruptionBiddingDocuments", "documentsForm",
                 "corruptionAwarded", "corruptionCancelled", "corruptionContracting"]

# This workaround fixes an error caused by missing "catch_phrase" class method
# for the "ru_RU" locale in Faker >= 0.7.4
fake_ru.add_provider(CompanyProviderEnUs)
fake_ru.add_provider(CompanyProviderRuRu)


def create_fake_sentence():
    return fake.sentence(nb_words=10, variable_nb_words=True)


def create_fake_funder():
    return fake.funders_data()


def get_fake_funder_scheme():
    return fake.funder_scheme()


def create_fake_amount(award_amount, tender_value_added_tax_included, contract_value_added_tax_included):
    min_amount_net = award_amount / 1.2
    range_amount_net = award_amount - min_amount_net
    half_min_amount_net = min_amount_net + range_amount_net / 2
    half_max_amount_net = half_min_amount_net + range_amount_net
    if tender_value_added_tax_included == True and contract_value_added_tax_included == True:
        return round(random.uniform(half_min_amount_net, award_amount), 2)
    if tender_value_added_tax_included == False and contract_value_added_tax_included == True:
        return round(random.uniform(award_amount, half_max_amount_net), 2)
    if tender_value_added_tax_included == True and contract_value_added_tax_included == False:
        return round(random.uniform(half_min_amount_net, award_amount), 2)
    if tender_value_added_tax_included == False and contract_value_added_tax_included == False:
        return round(random.uniform(half_min_amount_net, award_amount), 2)


def create_fake_amount_net(award_amount, tender_value_added_tax_included, contract_value_added_tax_included):
    min_amount_net = award_amount / 1.2
    range_amount_net = award_amount - min_amount_net
    half_min_amount_net = min_amount_net + range_amount_net / 2
    if tender_value_added_tax_included == True and contract_value_added_tax_included == True:
        return round(random.uniform(min_amount_net, half_min_amount_net), 2)
    if tender_value_added_tax_included == False and contract_value_added_tax_included == True:
        return round(random.uniform(half_min_amount_net, award_amount), 2)
    if tender_value_added_tax_included == True and contract_value_added_tax_included == False:
        return round(random.uniform(half_min_amount_net, award_amount), 2)
    if tender_value_added_tax_included == False and contract_value_added_tax_included == False:
        return round(random.uniform(half_min_amount_net, award_amount), 2)


def create_fake_amount_paid(contract_amount, contract_amountNet):
    minimum = contract_amountNet
    maximum = contract_amount
    range = maximum - minimum
    half_min_range = minimum + range / 2
    return round(random.uniform(minimum, half_min_range), 2)


def create_fake_number(min_number, max_number):
    return random.randint(int(min_number), int(max_number))


def create_fake_number_float(min_number, max_number):
    return round(random.uniform(float(min_number), float(max_number)), 3)


def create_fake_title():
    return u"[ТЕСТУВАННЯ] {}".format(fake.title())


def create_fake_date():
    return get_now().isoformat()


def create_fake_period(days=0, hours=0, minutes=0):
    data = {
        "startDate": get_now().isoformat(),
        "endDate": (get_now() + timedelta(days=days, hours=hours, minutes=minutes)).isoformat()
    }
    return data


def subtraction(value1, value2):
    if "." in str(value1) or "." in str(value2):
        return (float(value1) - float(value2))
    else:
        return (int(value1) - int(value2))


def create_fake_value_amount():
    return fake.random_int(min=1)


def get_number_of_minutes(days, accelerator):
    return 1440 * int(days) / accelerator


def field_with_id(prefix, sentence):
    return u"{}-{}: {}".format(prefix, fake.uuid4()[:8], sentence)


def translate_country_en(country):
    if country == u"Україна":
        return "Ukraine"
    else:
        raise Exception(u"Cannot translate country to english: {}".format(country))


def convert_amount(amount):
    return ("{:,}".format(float(amount))).replace(',', ' ').replace('.', ',')


def translate_country_ru(country):
    if country == u"Україна":
        return u"Украина"
    else:
        raise Exception(u"Cannot translate country to russian: {}".format(country))


def create_fake_doc():
    content = fake.text()
    suffix = fake.random_element(('.doc', '.docx', '.pdf'))
    prefix = "{}-{}{}".format("d", fake.uuid4()[:8], fake_en.word())
    tf = NamedTemporaryFile(delete=False, suffix=suffix, prefix=prefix)
    tf.write(content)
    tf.close()
    return tf.name.replace('\\', '\\\\'), os.path.basename(tf.name), content


def create_fake_IsoDurationType(
        years=0, months=0, days=0):
    return u"P{}Y{}M{}D".format(years, months, days)


def test_tender_data(params,
                     plan_data,
                     periods=("enquiry", "tender"),
                     submissionMethodDetails=None,
                     funders=None,
                     accelerator=None):
    submissionMethodDetails = submissionMethodDetails \
        if submissionMethodDetails else "quick"
    now = get_now()
    value_amount = round(random.uniform(3000, 99999999.99), 2)  # max value equals to budget of Ukraine in hryvnias
    vat_included = params.get('vat_included', True)
    data = {
        "mode": "test",
        "submissionMethodDetails": submissionMethodDetails,
        "description": fake.description(),
        "description_en": fake_en.sentence(nb_words=10, variable_nb_words=True),
        "description_ru": fake_ru.sentence(nb_words=10, variable_nb_words=True),
        "title": fake.title(),
        "title_en": fake_en.catch_phrase(),
        "title_ru": fake_ru.catch_phrase(),
        "procuringEntity": fake.procuringEntity(),
        "procurementMethodType": "belowThreshold",
        "value": {
            "amount": value_amount,
            "currency": u"UAH",
            "valueAddedTaxIncluded": vat_included
        },
        "minimalStep": {
            "amount": round(random.uniform(0.005, 0.03) * value_amount, 2),
            "currency": u"UAH",
            "valueAddedTaxIncluded": vat_included
        },
        "items": [],
        "features": []
    }
    if params.get("mode") == "open_framework":
        data["mainProcurementCategory"] = random.choice(['goods', 'services'])
    elif params.get("mode") == "open_competitive_dialogue":
        data["mainProcurementCategory"] = random.choice(['services', 'works'])
    else:
        data["mainProcurementCategory"] = random.choice(['goods', 'services', 'works'])
    accelerator = accelerator \
        if accelerator else params['intervals']['accelerator']
    data['procurementMethodDetails'] = 'quick, ' \
                                       'accelerator={}'.format(accelerator)
    data["procuringEntity"]["kind"] = "other"
    if data.get("mode") == "test":
        data["title"] = u"[ТЕСТУВАННЯ] {}".format(data["title"])
        data["title_en"] = u"[TESTING] {}".format(data["title_en"])
        data["title_ru"] = u"[ТЕСТИРОВАНИЕ] {}".format(data["title_ru"])
    period_dict = {}
    inc_dt = now
    for period_name in periods:
        period_dict[period_name + "Period"] = {}
        for i, j in zip(range(2), ("start", "end")):
            inc_dt += timedelta(minutes=params['intervals'][period_name][i])
            period_dict[period_name + "Period"][j + "Date"] = inc_dt.astimezone(TZ).isoformat()
    data.update(period_dict)
    if params.get('plan_tender'):
        data["procuringEntity"]["name"] = plan_data["data"]["procuringEntity"]["name"]
        data["procuringEntity"]["identifier"] = plan_data["data"]["procuringEntity"]["identifier"]
        cpv_group = plan_data["data"]["classification"]["id"]
    elif params.get('moz_integration'):
        cpv_group = 336
    elif params.get('road_index'):
        cpv_group = 'road'
    elif params.get('gmdn_index'):
        cpv_group = 'gmdn'
    else:
        cpv_group = fake.cpv()[:4]
    if params.get('number_of_lots'):
        data['lots'] = []
        for lot_number in range(params['number_of_lots']):
            lot_id = uuid4().hex
            new_lot = test_lot_data(data['value']['amount'], vat_included)
            data['lots'].append(new_lot)
            data['lots'][lot_number]['id'] = lot_id
            for i in range(params['number_of_items']):
                new_item = test_item_data(cpv_group)
                new_item['relatedLot'] = lot_id
                data['items'].append(new_item)
        value_amount = round(sum(lot['value']['amount'] for lot in data['lots']), 2)
        minimalStep = min(lot['minimalStep']['amount'] for lot in data['lots'])
        data['value']['amount'] = value_amount
        data['minimalStep']['amount'] = minimalStep
        if params.get('lot_meat'):
            new_feature = test_feature_data()
            new_feature['featureOf'] = "lot"
            data['lots'][0]['id'] = data['lots'][0].get('id', uuid4().hex)
            new_feature['relatedItem'] = data['lots'][0]['id']
            data['features'].append(new_feature)
    else:
        for i in range(params['number_of_items']):
            new_item = test_item_data(cpv_group)
            data['items'].append(new_item)
    milestones = params.get('number_of_milestones')
    if milestones:
        data['milestones'] = []
        percentage_data = percentage_generation(milestones)
        for percentage in percentage_data:
            milestone_element = test_milestone_data()
            milestone_element['sequenceNumber'] = len(data['milestones'])
            milestone_element['percentage'] = percentage
            if milestone_element['title'] == 'anotherEvent':
                milestone_element['description'] = fake.sentence(nb_words=40, variable_nb_words=True)
            if params.get('number_of_lots'):
                milestone_element['relatedLot'] = lot_id
            data["milestones"].append(milestone_element)
    if params.get('tender_meat'):
        new_feature = test_feature_data()
        new_feature.featureOf = "tenderer"
        data['features'].append(new_feature)
    if params.get('item_meat'):
        new_feature = test_feature_data()
        new_feature['featureOf'] = "item"
        data['items'][0]['id'] = data['items'][0].get('id', uuid4().hex)
        new_feature['relatedItem'] = data['items'][0]['id']
        data['features'].append(new_feature)
    if not data['features']:
        del data['features']
    if funders is not None:
        data['funders'] = [fake.funders_data() for _ in range(int(funders))]
    data['status'] = 'draft'
    return munchify(data)


def test_tender_data_planning(params):
    data = {
        "budget": {
            "amountNet": round(random.uniform(3000, 999999.99), 2),
            "description": fake.description(),
            "project": {
                "id": str(fake.random_int(min=1, max=999)),
                "name": fake.description(),
            },
            "currency": "UAH",
            "amount": round(random.uniform(3000, 99999999.99), 2),
            "id": str(fake.random_int(min=1, max=99999999999)) + "-" + str(fake.random_int(min=1, max=9)),
            "breakdown": [],
            "period": {
                "startDate": get_now().replace(hour=0, minute=0, second=0, microsecond=0).isoformat(),
                "endDate": get_now().replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
            }
        },
        "procuringEntity": {
            #"kind": "general",
            "identifier": {
                "scheme": "UA-EDR",
                "id": random.choice(["13313462", "00037256"]),
                "legalName": random.choice([u"Київський Тестовий Ліцей", u"Київська Тестова міська клінічна лікарня"]),
            },
            "address": {
                "countryName": "Україна",
                "postalCode": "01220",
                "region": "м. Київ",
                "streetAddress": "вул. Банкова, 11, корпус 1",
                "locality": "м. Київ"
            }
        },
        "tender": {
            "procurementMethod": "",
            "procurementMethodType": params['mode'],
            "tenderPeriod": {
                "startDate": get_now().replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
            }
        },
        "mode": "test",
        "items": [],
        "buyers": []
    }
    data["procuringEntity"]["name"] = data["procuringEntity"]["identifier"]["legalName"]
    if params.get("mode") == "aboveThresholdUA.defense":
        data["procuringEntity"]["kind"] = "defense"
    elif params.get("mode") in ["belowThreshold", "reporting"]:
        data["procuringEntity"]["kind"] = "other"
    else:
        data["procuringEntity"]["kind"] = random.choice(["general", "special", "central", "authority", "social"])
    buyers = test_buyers_data()
    buyers["name"] = buyers["identifier"]["legalName"]
    data['buyers'].append(buyers)
    if params.get('moz_integration'):
        id_cpv = 336
    elif params.get('road_index'):
        id_cpv = fake.road_cpv()[:4]
    elif params.get('gmdn_index'):
        id_cpv = fake.gmdn_cpv()[:4]
    else:
        id_cpv = fake.cpv()[:4]
    cpv_data = test_item_data(id_cpv)
    data.update(cpv_data)
    del data['deliveryDate']
    del data['description']
    del data['description_en']
    del data['description_ru']
    del data['deliveryAddress']
    del data['deliveryLocation']
    del data['quantity']
    del data['unit']
    for i in range(params['number_of_items']):
        item_data = test_item_data(id_cpv)
        del item_data['deliveryAddress']
        del item_data['deliveryLocation']
        item_data['deliveryDate']['endDate'] = (get_now() + timedelta(days=10)).replace(hour=0, minute=0, second=0,
                                                                                        microsecond=0).isoformat()
        del item_data['deliveryDate']['startDate']
        data['items'].append(item_data)
    if params['mode'] in mode_open:
        data["tender"]["procurementMethod"] = "open"
    if params['mode'] in mode_limited:
        data["tender"]["procurementMethod"] = "limited"
    if params.get('number_of_breakdown'):
        value_data = breakdown_value_generation(params['number_of_breakdown'], data['budget']['amount'])
        for value in value_data:
            breakdown_element = test_breakdown_data()
            breakdown_element['value']['amount'] = value
            data['budget']['breakdown'].append(breakdown_element)
    return munchify(data)


def test_tender_data_limited(params, plan_data):
    data = test_tender_data(params, plan_data)
    del data["submissionMethodDetails"]
    del data["minimalStep"]
    del data["enquiryPeriod"]
    del data["tenderPeriod"]
    for lot in data.get('lots', []):
        lot.pop('minimalStep', None)
    data["procuringEntity"]["kind"] = "general"
    data.update({"procurementMethodType": params['mode'], "procurementMethod": "limited"})
    if params['mode'] == "negotiation":
        cause_variants = (
            "resolvingInsolvency",
            "artPurchase",
            "contestWinner",
            "technicalReasons",
            "intProperty",
            "lastHope",
            "twiceUnsuccessful",
            "additionalPurchase",
            "additionalConstruction",
            "stateLegalServices"
        )
        cause = fake.random_element(cause_variants)
        data.update({
            "cause": cause,
            "causeDescription": fake.description()
        })
    elif params['mode'] == "negotiation.quick":
        cause_variants = (
            "resolvingInsolvency",
            "artPurchase",
            "contestWinner",
            "technicalReasons",
            "intProperty",
            "lastHope",
            "twiceUnsuccessful",
            "additionalPurchase",
            "additionalConstruction",
            "stateLegalServices",
            "emergency",
            "humanitarianAid",
            "contractCancelled",
            "activeComplaint"
        )
        cause = fake.random_element(cause_variants)
        data.update({
            "cause": cause,
            "causeDescription": fake.description()
        })
    #if params['mode'] in ("negotiation", "negotiation.quick"):
        #cause = fake.random_element(cause_variants)
    return munchify(data)


def test_feature_data():
    words = fake.words()
    feature = {
        "code": uuid4().hex,
        "title": field_with_id("f", fake.title()),
        "title_en": field_with_id('f', fake_en.sentence(nb_words=5, variable_nb_words=True)),
        "title_ru": field_with_id('f', fake_ru.sentence(nb_words=5, variable_nb_words=True)),
        "description": fake.description(),
        "enum": [
            {
                "value": 0.05,
                "title": words[0]
            },
            {
                "value": 0.01,
                "title": words[1]
            },
            {
                "value": 0,
                "title": words[2]
            }
        ]
    }
    return munchify(feature)


def test_question_data():
    data = {
        "author": fake.procuringTenderer(),
        "description": fake.description(),
        "title": field_with_id("q", fake.title())
    }
    del data['author']['scale']
    return munchify({'data': data})


def test_related_question(question, relation, obj_id):
    question.data.update({"questionOf": relation, "relatedItem": obj_id})
    return munchify(question)


def test_question_answer_data():
    return munchify({
        "data": {
            "answer": fake.sentence(nb_words=40, variable_nb_words=True)
        }
    })


def test_complaint_data():
    data = {
        "author": fake.procuringTenderer(),
        "description": fake.description(),
        "title": field_with_id("q", fake.title()),
        "type": "complaint"
    }
    del data['author']['scale']
    return munchify({'data': data})


def test_payment_data(token, complaint_value, complaint_uaid):
    data = {
            "amount": str(complaint_value),
            "currency": "UAH",
            "description": generate_payment_description(token, complaint_uaid),
            "type": "credit",
            "date_oper": get_now().isoformat(),
            "account": "UA723004380000026001503374077",
            "okpo": "14360570",
            "mfo": "123456",
            "name": u"Плат.интер-эквайрин через LiqPay"
    }
    return data


def generate_payment_description(token, complaint_uaid):
    full_hash = hashlib.sha512(token).hexdigest()
    short_hash = full_hash[0:8]
    description = complaint_uaid + '-' + short_hash + ' [TESTING, ROBOT TESTS]'
    return description


def test_accept_complaint_data():
    data = {
        "status": "accepted",
        "reviewDate": get_now().isoformat(),
        "reviewPlace": "Place of review"
    }
    return munchify({'data': data})


def test_reject_complaint_data():
    data = {
        "rejectReason": random.choice(["lawNonCompliance", "buyerViolationsCorrected", "alreadyExists", "tenderCancelled"])
    }
    return munchify({'data': data})


def test_award_complaint_data():
    data = {
        "author": fake.procuringTenderer(),
        "description": fake.description(),
        "title": field_with_id("q", fake.title()),
        "type": "complaint"
    }
    del data['author']['scale']
    return munchify({'data': data})


def test_claim_data():
    data = {
        "author": fake.procuringTenderer(),
        "description": fake.description(),
        "title": field_with_id("q", fake.title()),
        "type": "claim"
    }
    del data['author']['scale']
    return munchify({'data': data})


def test_claim_answer_data(status):
    return munchify({
        "data": {
            "status": "answered",
            "resolutionType": status,
            "tendererAction": fake.sentence(nb_words=10, variable_nb_words=True),
            "resolution": fake.sentence(nb_words=15, variable_nb_words=True)
        }
    })


def test_confirm_data(id):
    return munchify({
        "data": {
            "status": "active",
            "id": id
        }
    })


def test_cancel_pending_data(id):
    return munchify({
        "data": {
            "status": "pending",
            "id": id
        }
    })


def test_submit_claim_data(claim_id):
    return munchify({
        "data": {
            "id": claim_id,
            "status": "claim"
        }
    })


def test_complaint_reply_data():
    return munchify({
        "data": {
            "status": "resolved"
        }
    })


def test_bid_competitive_data():
    bid = munchify({
        "data": {
            "tenderers": [
                fake.procuringTenderer()
            ]
        }
    })
    if len(used_identifier_id) == 3:
        del used_identifier_id[0]
    id = bid.data.tenderers[0].identifier.id
    while (id in used_identifier_id):
        bid = munchify({
            "data": {
                "tenderers": [
                    fake.procuringTenderer()
                ]
            }
        })
        id = bid.data.tenderers[0].identifier.id
    used_identifier_id.append(id)
    bid.data.tenderers[0].address.countryName_en = translate_country_en(bid.data.tenderers[0].address.countryName)
    bid.data.tenderers[0].address.countryName_ru = translate_country_ru(bid.data.tenderers[0].address.countryName)
    bid.data['status'] = 'draft'
    return bid


def test_bid_competitive_data_stage_2(id):
    bid = munchify({
        "data": {
            "tenderers": [
                fake.procuringTenderer()
            ]
        }
    })
    bid.data.tenderers[0].identifier.id = id
    bid.data.tenderers[0].address.countryName_en = translate_country_en(bid.data.tenderers[0].address.countryName)
    bid.data.tenderers[0].address.countryName_ru = translate_country_ru(bid.data.tenderers[0].address.countryName)
    bid.data['status'] = 'draft'
    return bid


def test_bid_data():
    bid = munchify({
        "data": {
            "tenderers": [
                fake.procuringTenderer()
            ]
        }
    })
    bid.data.tenderers[0].address.countryName_en = translate_country_en(bid.data.tenderers[0].address.countryName)
    bid.data.tenderers[0].address.countryName_ru = translate_country_ru(bid.data.tenderers[0].address.countryName)
    bid.data['status'] = 'draft'
    return bid


def test_bid_value(max_value_amount, vat_included):
    return munchify({
        "value": {
            "currency": "UAH",
            "amount": round(random.uniform((0.95 * max_value_amount), max_value_amount), 2),
            "valueAddedTaxIncluded": vat_included
        }
    })


def test_bid_value_esco(tender_data):
    annual_cost = []
    for i in range(0, 21):
        cost = round(random.uniform(1, 100), 2)
        annual_cost.append(cost)
    if tender_data['fundingKind'] == "budget":
        yearly_percentage = round(random.uniform(0.01, float(tender_data['yearlyPaymentsPercentageRange'])), 5)
    else:
        yearly_percentage = 0.8
    # when tender fundingKind is budget, yearlyPaymentsPercentageRange should be less or equal 0.8, and more or equal 0
    # when tender fundingKind is other, yearlyPaymentsPercentageRange should be equal 0.8
    return munchify({
        "value": {
            "currency": "UAH",
            "valueAddedTaxIncluded": True,
            "yearlyPaymentsPercentage": yearly_percentage,
            "annualCostsReduction": annual_cost,
            "contractDuration": {
                "years": random.randint(7, 14),
                "days": random.randint(1, 364)
            }
        }
    })


def test_bid_data_selection(data, index):
    bid = munchify({
        "data": {
            "tenderers": [
                data['agreements'][0]['contracts'][index]['suppliers'][0]
            ]
        }
    })
    bid.data['status'] = 'draft'
    bid.data['parameters'] = data['agreements'][0]['contracts'][index]['parameters']
    bid.data['lotValues'] = [test_bid_value(data['agreements'][0]['contracts'][index]['value']['amount'],
                                            data['agreements'][0]['contracts'][index]['value'][
                                                'valueAddedTaxIncluded'])]
    return bid


def test_supplier_data():
    return munchify({
        "data": {
            "suppliers": [
                fake.procuringTenderer()
            ],
            "value": {
                "amount": fake.random_int(min=1),
                "currency": "UAH",
                "valueAddedTaxIncluded": True
            },
            "qualified": True
        }
    })


def test_item_data(cpv=None):
    data = fake.fake_item(cpv)
    data["description"] = field_with_id("i", data["description"])
    data["description_en"] = field_with_id("i", data["description_en"])
    data["description_ru"] = field_with_id("i", data["description_ru"])
    startDate = fake.random_int(min=1, max=30)
    endDate = startDate + fake.random_int(min=1, max=7)
    data["deliveryDate"] = {
        "startDate": (get_now() + timedelta(days=startDate)).astimezone(TZ).replace(hour=0, minute=0, second=0,
                                                                                    microsecond=0).isoformat(),
        "endDate": (get_now() + timedelta(days=endDate)).astimezone(TZ).replace(hour=0, minute=0, second=0,
                                                                                microsecond=0).isoformat()
    }
    data["deliveryAddress"]["countryName_en"] = translate_country_en(data["deliveryAddress"]["countryName"])
    data["deliveryAddress"]["countryName_ru"] = translate_country_ru(data["deliveryAddress"]["countryName"])
    return munchify(data)


def test_invalid_features_data():
    return [
        {
            "code": "ee3e24bc17234a41bd3e3a04cc28e9c6",
            "featureOf": "tenderer",
            "title": fake.title(),
            "description": fake.description(),
            "enum": [
                {
                    "value": 0.35,
                    "title": fake.word()
                },
                {
                    "value": 0,
                    "title": fake.word()
                }
            ]
        }
    ]


def test_lot_data(max_value_amount, vat_included=True):
    value_amount = round(random.uniform(1, max_value_amount), 2)
    return munchify(
        {
            "description": fake.description(),
            "title": field_with_id('l', fake.title()),
            "title_en": field_with_id('l', fake_en.sentence(nb_words=5, variable_nb_words=True)),
            "title_ru": field_with_id('l', fake_ru.sentence(nb_words=5, variable_nb_words=True)),
            "value": {
                "currency": "UAH",
                "amount": value_amount,
                "valueAddedTaxIncluded": vat_included
            },
            "minimalStep": {
                "currency": "UAH",
                "amount": round(random.uniform(0.005, 0.03) * value_amount, 2),
                "valueAddedTaxIncluded": vat_included
            },
            "status": "active"
        })


def test_lot_document_data(document, lot_id):
    document.data.update({"documentOf": "lot", "relatedItem": lot_id})
    return munchify(document)


def test_change_document_data(document, change_id):
    document.data.update({"documentOf": "change", "relatedItem": change_id})
    return munchify(document)


def test_tender_data_openua(params, submissionMethodDetails, plan_data):
    # We should not provide any values for `enquiryPeriod` when creating
    # an openUA or openEU procedure. That field should not be present at all.
    # Therefore, we pass a nondefault list of periods to `test_tender_data()`.
    data = test_tender_data(params, plan_data, ('tender',), submissionMethodDetails)
    data['procurementMethodType'] = 'aboveThresholdUA'
    data['procuringEntity']['kind'] = 'general'
    return data


def test_tender_data_openua_defense(params, submissionMethodDetails, plan_data):
    """We should not provide any values for `enquiryPeriod` when creating
    an openUA, openEU or openUA_defense procedure. That field should not be present at all.
    Therefore, we pass a nondefault list of periods to `test_tender_data()`."""
    data = test_tender_data(params, plan_data, ('tender',), submissionMethodDetails)
    data['procurementMethodType'] = 'aboveThresholdUA.defense'
    data['procuringEntity']['kind'] = 'defense'
    return data


def test_tender_data_openeu(params, submissionMethodDetails, plan_data):
    # We should not provide any values for `enquiryPeriod` when creating
    # an openUA or openEU procedure. That field should not be present at all.
    # Therefore, we pass a nondefault list of periods to `test_tender_data()`.
    data = test_tender_data(params, plan_data, ('tender',), submissionMethodDetails)
    data['procurementMethodType'] = 'aboveThresholdEU'
    data['title_en'] = "[TESTING]"
    for item_number, item in enumerate(data['items']):
        item['description_en'] = "Test item #{}".format(item_number)
    data['procuringEntity']['name_en'] = fake_en.name()
    data['procuringEntity']['contactPoint']['name_en'] = fake_en.name()
    data['procuringEntity']['contactPoint']['availableLanguage'] = "en"
    data['procuringEntity']['identifier'][
        'legalName_en'] = u"Institution \"Vinnytsia City Council primary and secondary general school № 10\""
    data['procuringEntity']['kind'] = 'general'
    return data


def test_tender_data_framework_agreement(params, submissionMethodDetails, plan_data):
    data = test_tender_data_openeu(params, submissionMethodDetails, plan_data)
    data['procurementMethodType'] = 'closeFrameworkAgreementUA'
    data['maxAwardsCount'] = fake.random_int(min=3, max=5)
    data['agreementDuration'] = create_fake_IsoDurationType(
        years=fake.random_int(min=1, max=3),
        months=fake.random_int(min=1, max=8),
        days=fake.random_int(min=1, max=6)
    )
    return data


def test_tender_data_competitive_dialogue(params, submissionMethodDetails, plan_data):
    # We should not provide any values for `enquiryPeriod` when creating
    # an openUA or openEU procedure. That field should not be present at all.
    # Therefore, we pass a nondefault list of periods to `test_tender_data()`.
    data = test_tender_data(params, plan_data, ('tender',), submissionMethodDetails)
    if params.get('dialogue_type') == 'UA':
        data['procurementMethodType'] = 'competitiveDialogueUA'
    else:
        data['procurementMethodType'] = 'competitiveDialogueEU'
        data['procuringEntity']['contactPoint']['availableLanguage'] = "en"
    data['title_en'] = "[TESTING] {}".format(fake_en.sentence(nb_words=3, variable_nb_words=True))
    for item in data['items']:
        item['description_en'] = fake_en.sentence(nb_words=3, variable_nb_words=True)
    data['procuringEntity']['name_en'] = fake_en.name()
    data['procuringEntity']['contactPoint']['name_en'] = fake_en.name()
    data['procuringEntity']['identifier']['legalName_en'] = fake_en.sentence(nb_words=10, variable_nb_words=True)
    data['procuringEntity']['kind'] = 'general'
    return data


def test_tender_data_selection(procedure_intervals, params, submissionMethodDetails, tender_data=None, plan_data=None):
    intervals = procedure_intervals['framework_selection']
    params['intervals'] = intervals
    data = test_tender_data(params, plan_data, (), submissionMethodDetails)
    data['title_en'] = "[TESTING]"
    data['procuringEntity'] = tender_data['data']['procuringEntity']
    del data['procuringEntity']['contactPoint']['availableLanguage']
    data['procurementMethodType'] = 'closeFrameworkAgreementSelectionUA'
    data['items'] = tender_data['data']['items']
    data['lots'] = tender_data['data']['lots']
    data['agreements'] = [{'id': tender_data['data']['agreements'][0]['id']}]
    del data['value']
    del data['minimalStep']
    return munchify({'data': data})


def test_change_data():
    return munchify(
        {
            "data":
                {
                    "rationale": fake.description(),
                    "rationale_en": fake_en.sentence(nb_words=10, variable_nb_words=True),
                    "rationale_ru": fake_ru.sentence(nb_words=10, variable_nb_words=True),
                    "rationaleTypes": fake.rationaleTypes(amount=3),
                    "status": "pending"
                }
        })


def test_agreement_change_data(rationaleType):
    return munchify(
        {
            "data":
                {
                    "rationale": fake.description(),
                    "rationale_en": fake_en.sentence(nb_words=10, variable_nb_words=True),
                    "rationale_ru": fake_ru.sentence(nb_words=10, variable_nb_words=True),
                    "rationaleType": rationaleType,
                }
        })


def test_modification_data(item_id, field_name, field_value):
    data = {
        "modifications": [
            {
                "itemId": item_id,
                field_name: field_value
            }
        ]
    }
    return munchify({'data': data})


def get_hash(file_contents):
    return ("md5:" + hashlib.md5(file_contents).hexdigest())


def test_monitoring_data(tender_id, accelerator=None):
    data = {"reasons": [random.choice(["public", "fiscal", "indicator", "authorities", "media"])],
            "tender_id": tender_id,
            "procuringStages": [random.choice(["awarding", "contracting", "planning"])],
            "parties": [test_party()],
            "mode": "test",
            'monitoringDetails': 'quick, ' 'accelerator={}'.format(accelerator)}
    return munchify({'data': data})


def test_party():
    party = fake.procuringEntity()
    party["roles"] = [random.choice(['sas', 'risk_indicator'])]
    party["name"] = "The State Audit Service of Ukraine"
    return munchify(party)


def test_dialogue():
    return munchify(
        {
            "data":
                {
                    "title": fake_en.sentence(nb_words=10, variable_nb_words=True),
                    "description": fake_en.sentence(nb_words=10, variable_nb_words=True)
                }
        })


def test_conclusion(violationOccurred, relatedParty_id):
    return munchify(
        {
            "data": {
                "conclusion": {
                    "violationOccurred": violationOccurred,
                    "violationType": random.choice(violationType),
                    "relatedParty": relatedParty_id,
                }
            }
        })


def test_status_data(status, relatedParty_id=None):
    data = {
        "data": {
            "status": status
        }
    }
    if status in ('stopped', 'cancelled'):
        data["data"]["cancellation"] = {}
        data["data"]["cancellation"]["description"] = fake_en.sentence(nb_words=10, variable_nb_words=True)
        data["data"]["cancellation"]["relatedParty"] = relatedParty_id
    return munchify(data)


def test_elimination_report(corruption, relatedParty_id):
    return munchify({
        "data": {
            "eliminationResolution": {
                "resultByType": {
                    corruption: random.choice(["eliminated", "not_eliminated", "no_mechanism"])
                },
                "relatedParty": relatedParty_id,
                "result": random.choice(["completely", "partly", "none"]),
                "description": fake_en.sentence(nb_words=10, variable_nb_words=True)
            }
        }
    })


def test_tender_data_esco(params, submissionMethodDetails, plan_data):
    data = test_tender_data(params, plan_data, ('tender',), submissionMethodDetails)
    data['procurementMethodType'] = 'esco'
    data['title_en'] = "[TESTING]"
    for item_number, item in enumerate(data['items']):
        item['description_en'] = "Test item #{}".format(item_number)
        del item['unit']
    data['procuringEntity']['name_en'] = fake_en.name()
    data['procuringEntity']['contactPoint']['name_en'] = fake_en.name()
    data['procuringEntity']['contactPoint']['availableLanguage'] = "en"
    data['procuringEntity']['identifier']['legalName_en'] = fake_en.sentence(nb_words=10, variable_nb_words=True)
    data['procuringEntity']['kind'] = 'general'
    data['minimalStepPercentage'] = float(round(random.uniform(0.015, 0.03), 5))
    data['fundingKind'] = params['fundingKind']
    data['NBUdiscountRate'] = float(round(random.uniform(0, 0.99), 5))
    percentage_list = []
    del data["value"]
    del data["minimalStep"]
    del data["milestones"]
    for index in range(params['number_of_lots']):
        data['lots'][index]['fundingKind'] = data['fundingKind']
        if index == 0:
            data['lots'][index]['minimalStepPercentage'] = data['minimalStepPercentage']
        else:
            data['lots'][index]['minimalStepPercentage'] = round((float(data['minimalStepPercentage']) - 0.0002), 5)
        if data['fundingKind'] == "budget":
            data['lots'][index]['yearlyPaymentsPercentageRange'] = float(round(random.uniform(0.01, 0.8), 5))
        else:
            data['lots'][index]['yearlyPaymentsPercentageRange'] = 0.8
        percentage_list.append(data['lots'][index]['yearlyPaymentsPercentageRange'])
        del data['lots'][index]['value']
        del data['lots'][index]['minimalStep']
    if params['number_of_lots'] == 0:
        if data['fundingKind'] == "budget":
            data['yearlyPaymentsPercentageRange'] = float(round(random.uniform(0.01, 0.8), 3))
        else:
            data['yearlyPaymentsPercentageRange'] = 0.8
    else:
        data['yearlyPaymentsPercentageRange'] = min(percentage_list)
    for index in range(params['number_of_items']):
        del data['items'][index]['deliveryDate']
    return data


def test_milestone_data():
    return munchify({
        "code": random.choice(["prepayment", "postpayment"]),
        "title": fake.milestone_title(),
        "duration": {
            "type": random.choice(["working", "banking", "calendar"]),
            "days": random.randint(1, 364)
        },
        "type": "financing"
    })


def percentage_generation(number_of_milestones):
    # input: number_of_milestones 1, 2, 3, ...
    # output: list of percentage numbers
    percentage_data = [random.randint(1, round(100 / number_of_milestones)) for _ in range(number_of_milestones - 1)]
    percentage_data.append(100 - sum(percentage_data))
    return percentage_data


def invalid_INN_data():
    return munchify({
        "scheme": "INN",
        "description": "Insulin (human)",
        "id": "insulin (human)"
    })


def invalid_cost_data():
    return munchify({
        "scheme": "UA-ROAD",
        "id": "H-08",
        "description": "Бориспіль - Дніпро - Запоріжжя (через м. Кременчук) - Маріуполь"
    })


def invalid_gmdn_data():
    return munchify({
        "scheme": "GMDN",
        "id": "10082",
        "description": "Змішувач амальгами для стоматології"
    })


def test_buyers_data():
    buyers = {
        "kind": "general",
        "identifier": {
            "scheme": "UA-EDR",
            "id": random.choice(["13313462", "00037256"]),
            "legalName": random.choice([u"Київський Тестовий Ліцей", u"Київська Тестова міська клінічна лікарня"]),
        },
        "address": {
            "countryName": "Україна",
            "postalCode": "01220",
            "region": "м. Київ",
            "streetAddress": "вул. Банкова, 11, корпус 1",
            "locality": "м. Київ"
        }
    }
    return munchify(buyers)


def invalid_buyers_data():
    buyers = {
        "identifier": {
            "scheme": "UA-EDR",
            "id": "13313462",
            "legalName": "Київський Тестовий Ліцей",
        },
        "name": "Київський Тестовий Ліцей"
    }
    return munchify(buyers)


def test_plan_cancel_data():
    plan_cancel = {
        "cancellation": {
            "reason": "Підстава для скасування",
            "reason_en": "Reason of the cancellation"
        }
    }
    return munchify(plan_cancel)


def test_confirm_plan_cancel_data():
    return munchify({
        "data": {
            "cancellation": {
                "status": "active"
            }
        }
    })


def test_breakdown_data():
    return munchify({
        "title": random.choice(["state", "local", "crimea", "own", "fund", "loan", "other"]),
        "description": fake.description(),
        "value": {
            "currency": "UAH"
        }
    })


def breakdown_value_generation(number_of_breakdown, plan_value):
    value_data = [round(random.uniform(1, plan_value / number_of_breakdown), 2) for _ in range(number_of_breakdown - 1)]
    value_data.append(round(plan_value - sum(value_data), 2))
    return value_data


def test_cancellation_data(procurement_method_type):
    if procurement_method_type == "aboveThresholdUA.defense":
        result = random.choice(["noDemand", "unFixable", "expensesCut"])
    elif procurement_method_type in ["negotiation", "negotiation.quick"]:
        result = random.choice(["noObjectiveness", "unFixable", "noDemand", "expensesCut", "dateViolation"])
    elif procurement_method_type == "belowThreshold":
        result = random.choice(["noDemand", "unFixable", "expensesCut"])
    else:
        result = random.choice(["noDemand", "unFixable", "forceMajeure", "expensesCut"])
    return munchify({"reasonType": result})


def test_24_hours_data():
    return munchify({
        "data": {
                "code": "24h",
                "description": create_fake_sentence()
        }
    })