# Copyright © 2019 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests to assure the fees end-point.

Test-Suite to ensure that the /fees endpoint is working as expected.
"""
import json
from datetime import date, timedelta

from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType
from pay_api.schemas import utils as schema_utils
from pay_api.utils.enums import Role
from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header


def test_fees_with_corp_type_and_filing_type(session, client, jwt, app):
    """Assert that the endpoint returns 200."""
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}
    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]


def test_fees_with_corp_type_and_filing_type_with_valid_start_date(session, client, jwt, app):
    """Assert that the endpoint returns 200."""
    # Insert a record first and then query for it
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    now = date.today()
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100),
        now - timedelta(1))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?valid_date={now}', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    assert not schema_utils.validate(rv.json, 'problem')[0]


def test_fees_with_corp_type_and_filing_type_with_invalid_start_date(session, client, jwt, app):
    """Assert that the endpoint returns 400."""
    # Insert a record first and then query for it
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    now = date.today()
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100),
        now + timedelta(1))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?valid_date={now}', headers=headers)
    assert rv.status_code == 400
    assert schema_utils.validate(rv.json, 'problem')[0]
    assert not schema_utils.validate(rv.json, 'fees')[0]


def test_fees_with_corp_type_and_filing_type_with_valid_end_date(session, client, jwt, app):
    """Assert that the endpoint returns 200."""
    # Insert a record first and then query for it
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    now = date.today()
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100),
        now - timedelta(1),
        now)
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?valid_date={now}', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]


def test_fees_with_corp_type_and_filing_type_with_invalid_end_date(session, client, jwt, app):
    """Assert that the endpoint returns 400."""
    # Insert a record first and then query for it
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    now = date.today()
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100),
        now - timedelta(2),
        now - timedelta(1))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?valid_date={now}', headers=headers)
    assert rv.status_code == 400
    assert schema_utils.validate(rv.json, 'problem')[0]


def test_calculate_fees_with_waive_fees(session, client, jwt, app):
    """Assert that the endpoint returns 201."""
    token = jwt.create_jwt(get_claims(role='staff'), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?waiveFees=true', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    assert rv.json.get('filingFees') == 0


def test_calculate_fees_with_waive_fees_unauthorized(session, client, jwt, app):
    """Assert that the endpoint returns 201."""
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?waiveFees=true', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    assert rv.json.get('filingFees') == 100


def test_fees_with_quantity(session, client, jwt, app):
    """Assert that the endpoint returns 200."""
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}
    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}?quantity=10', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]


def test_calculate_fees_for_service_fee(session, client, jwt, app):
    """Assert that the endpoint returns 201."""
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'
    service_fee = factory_fee_model('SF01', 1.5)
    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 100),
        service_fee=service_fee)

    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    assert rv.json.get('filingFees') == 100
    assert rv.json.get('serviceFees') == 1.5


def test_calculate_fees_with_zero_service_fee(session, client, jwt, app):
    """Assert that service fee is zero if the filing fee is zero."""
    token = jwt.create_jwt(get_claims(), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

    corp_type = 'XX'
    filing_type_code = 'XOTANN'

    factory_fee_schedule_model(
        factory_filing_type_model('XOTANN', 'TEST'),
        factory_corp_type_model('XX', 'TEST'),
        factory_fee_model('XXX', 0))
    rv = client.get(f'/api/v1/fees/{corp_type}/{filing_type_code}', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    assert rv.json.get('filingFees') == 0
    assert rv.json.get('serviceFees') == 0


def test_fee_for_account_fee_settings(session, client, jwt, app):
    """Assert that the endpoint returns 200."""
    token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}
    rv = client.post('/api/v1/accounts', data=json.dumps(get_gov_account_payload()),
                     headers=headers)

    account_id = rv.json.get('authAccountId')

    # Create account fee details.
    token = jwt.create_jwt(get_claims(role=Role.MANAGE_ACCOUNTS.value), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}
    client.post(f'/api/v1/accounts/{account_id}/fees', data=json.dumps({'accountFees': [
        {
            'applyFilingFees': False,
            'serviceFeeCode': 'TRF02',  # 1.0
            'product': 'BUSINESS'
        }
    ]}), headers=headers)

    # Get fee for this account.
    token = jwt.create_jwt(get_claims(role=Role.EDITOR.value), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': account_id}
    rv = client.get('/api/v1/fees/BEN/BCANN', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    # assert filing fee is not applied and service fee is applied
    assert rv.json.get('filingFees') == 0
    assert rv.json.get('serviceFees') == 1.0

    # Now change the settings to apply filing fees and assert
    token = jwt.create_jwt(get_claims(role=Role.MANAGE_ACCOUNTS.value), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}
    client.put(f'/api/v1/accounts/{account_id}/fees/BUSINESS', data=json.dumps({
        'applyFilingFees': True,
        'serviceFeeCode': 'TRF01',  # 1.5
        'product': 'BUSINESS'
    }), headers=headers)

    # Get fee for this account.
    token = jwt.create_jwt(get_claims(role=Role.EDITOR.value), token_header)
    headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': account_id}
    rv = client.get('/api/v1/fees/BEN/BCANN', headers=headers)
    assert rv.status_code == 200
    assert schema_utils.validate(rv.json, 'fees')[0]
    # assert filing fee is applied and service fee is applied
    assert rv.json.get('filingFees') > 0
    assert rv.json.get('serviceFees') == 1.5


def factory_filing_type_model(
        filing_type_code: str,
        filing_description: str = 'TEST'):
    """Return the filing type model."""
    filing_type = FilingType(code=filing_type_code,
                             description=filing_description)
    filing_type.save()
    return filing_type


def factory_fee_model(
        fee_code: str,
        amount: int):
    """Return the fee code model."""
    fee_code_master = FeeCode(code=fee_code,
                              amount=amount)
    fee_code_master.save()
    return fee_code_master


def factory_corp_type_model(
        corp_type_code: str,
        corp_type_description: str):
    """Return the corp type model."""
    corp_type = CorpType(code=corp_type_code,
                         description=corp_type_description)
    corp_type.save()
    return corp_type


def factory_fee_schedule_model(
        filing_type: FilingType,
        corp_type: CorpType,
        fee_code: FeeCode,
        fee_start_date: date = date.today(),
        fee_end_date: date = None,
        service_fee: FeeCode = None):
    """Return the fee schedule model."""
    fee_schedule = FeeSchedule(filing_type_code=filing_type.code,
                               corp_type_code=corp_type.code,
                               fee_code=fee_code.code,
                               fee_start_date=fee_start_date,
                               fee_end_date=fee_end_date
                               )
    if service_fee:
        fee_schedule.service_fee_code = service_fee.code
    fee_schedule.save()
    return fee_schedule

[((51, 10, 51, 22), 'datetime.date.today', 'date.today', ({}, {}), '()', False, 'from datetime import date, timedelta\n'), ((71, 10, 71, 22), 'datetime.date.today', 'date.today', ({}, {}), '()', False, 'from datetime import date, timedelta\n'), ((91, 10, 91, 22), 'datetime.date.today', 'date.today', ({}, {}), '()', False, 'from datetime import date, timedelta\n'), ((111, 10, 111, 22), 'datetime.date.today', 'date.today', ({}, {}), '()', False, 'from datetime import date, timedelta\n'), ((266, 18, 267, 60), 'pay_api.models.FilingType', 'FilingType', (), '', False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((276, 22, 277, 44), 'pay_api.models.FeeCode', 'FeeCode', (), '', False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((286, 16, 287, 59), 'pay_api.models.CorpType', 'CorpType', (), '', False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((296, 31, 296, 43), 'datetime.date.today', 'date.today', ({}, {}), '()', False, 'from datetime import date, timedelta\n'), ((300, 19, 305, 32), 'pay_api.models.FeeSchedule', 'FeeSchedule', (), '', False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((30, 27, 30, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((40, 11, 40, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(40, 33, 40, 40): 'rv.json', (40, 42, 40, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((46, 27, 46, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((59, 11, 59, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(59, 33, 59, 40): 'rv.json', (59, 42, 59, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((66, 27, 66, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((79, 11, 79, 52), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(79, 33, 79, 40): 'rv.json', (79, 42, 79, 51): '"""problem"""'}, {}), "(rv.json, 'problem')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((86, 27, 86, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((100, 11, 100, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(100, 33, 100, 40): 'rv.json', (100, 42, 100, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((106, 27, 106, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((120, 11, 120, 52), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(120, 33, 120, 40): 'rv.json', (120, 42, 120, 51): '"""problem"""'}, {}), "(rv.json, 'problem')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((125, 27, 125, 51), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((136, 11, 136, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(136, 33, 136, 40): 'rv.json', (136, 42, 136, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((142, 27, 142, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((153, 11, 153, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(153, 33, 153, 40): 'rv.json', (153, 42, 153, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((159, 27, 159, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((169, 11, 169, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(169, 33, 169, 40): 'rv.json', (169, 42, 169, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((174, 27, 174, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((188, 11, 188, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(188, 33, 188, 40): 'rv.json', (188, 42, 188, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((195, 27, 195, 39), 'tests.utilities.base_test.get_claims', 'get_claims', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((207, 11, 207, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(207, 33, 207, 40): 'rv.json', (207, 42, 207, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((214, 27, 214, 61), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((222, 27, 222, 70), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((233, 27, 233, 61), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((237, 11, 237, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(237, 33, 237, 40): 'rv.json', (237, 42, 237, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((243, 27, 243, 70), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((252, 27, 252, 61), 'tests.utilities.base_test.get_claims', 'get_claims', (), '', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((256, 11, 256, 49), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(256, 33, 256, 40): 'rv.json', (256, 42, 256, 48): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((56, 14, 56, 26), 'datetime.timedelta', 'timedelta', ({(56, 24, 56, 25): '(1)'}, {}), '(1)', False, 'from datetime import date, timedelta\n'), ((60, 15, 60, 56), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(60, 37, 60, 44): 'rv.json', (60, 46, 60, 55): '"""problem"""'}, {}), "(rv.json, 'problem')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((76, 14, 76, 26), 'datetime.timedelta', 'timedelta', ({(76, 24, 76, 25): '(1)'}, {}), '(1)', False, 'from datetime import date, timedelta\n'), ((80, 15, 80, 53), 'pay_api.schemas.utils.validate', 'schema_utils.validate', ({(80, 37, 80, 44): 'rv.json', (80, 46, 80, 52): '"""fees"""'}, {}), "(rv.json, 'fees')", True, 'from pay_api.schemas import utils as schema_utils\n'), ((96, 14, 96, 26), 'datetime.timedelta', 'timedelta', ({(96, 24, 96, 25): '(1)'}, {}), '(1)', False, 'from datetime import date, timedelta\n'), ((116, 14, 116, 26), 'datetime.timedelta', 'timedelta', ({(116, 24, 116, 25): '(2)'}, {}), '(2)', False, 'from datetime import date, timedelta\n'), ((117, 14, 117, 26), 'datetime.timedelta', 'timedelta', ({(117, 24, 117, 25): '(1)'}, {}), '(1)', False, 'from datetime import date, timedelta\n'), ((224, 60, 230, 7), 'json.dumps', 'json.dumps', ({(224, 71, 230, 6): "{'accountFees': [{'applyFilingFees': False, 'serviceFeeCode': 'TRF02',\n    'product': 'BUSINESS'}]}"}, {}), "({'accountFees': [{'applyFilingFees': False, 'serviceFeeCode':\n    'TRF02', 'product': 'BUSINESS'}]})", False, 'import json\n'), ((245, 68, 249, 6), 'json.dumps', 'json.dumps', ({(245, 79, 249, 5): "{'applyFilingFees': True, 'serviceFeeCode': 'TRF01', 'product': 'BUSINESS'}"}, {}), "({'applyFilingFees': True, 'serviceFeeCode': 'TRF01', 'product':\n    'BUSINESS'})", False, 'import json\n'), ((216, 57, 216, 82), 'tests.utilities.base_test.get_gov_account_payload', 'get_gov_account_payload', ({}, {}), '()', False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n')]