# 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

[((2064, 2076), 'datetime.date.today', 'date.today', ([], {}), '()\n', (2074, 2076), False, 'from datetime import date, timedelta\n'), ((2927, 2939), 'datetime.date.today', 'date.today', ([], {}), '()\n', (2937, 2939), False, 'from datetime import date, timedelta\n'), ((3786, 3798), 'datetime.date.today', 'date.today', ([], {}), '()\n', (3796, 3798), False, 'from datetime import date, timedelta\n'), ((4600, 4612), 'datetime.date.today', 'date.today', ([], {}), '()\n', (4610, 4612), False, 'from datetime import date, timedelta\n'), ((11302, 11367), 'pay_api.models.FilingType', 'FilingType', ([], {'code': 'filing_type_code', 'description': 'filing_description'}), '(code=filing_type_code, description=filing_description)\n', (11312, 11367), False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((11572, 11609), 'pay_api.models.FeeCode', 'FeeCode', ([], {'code': 'fee_code', 'amount': 'amount'}), '(code=fee_code, amount=amount)\n', (11579, 11609), False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((11845, 11909), 'pay_api.models.CorpType', 'CorpType', ([], {'code': 'corp_type_code', 'description': 'corp_type_description'}), '(code=corp_type_code, description=corp_type_description)\n', (11853, 11909), False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((12131, 12143), 'datetime.date.today', 'date.today', ([], {}), '()\n', (12141, 12143), False, 'from datetime import date, timedelta\n'), ((12278, 12446), 'pay_api.models.FeeSchedule', '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'}), '(filing_type_code=filing_type.code, corp_type_code=corp_type.\n    code, fee_code=fee_code.code, fee_start_date=fee_start_date,\n    fee_end_date=fee_end_date)\n', (12289, 12446), False, 'from pay_api.models import CorpType, FeeCode, FeeSchedule, FilingType\n'), ((1153, 1165), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (1163, 1165), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((1621, 1659), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (1642, 1659), True, 'from pay_api.schemas import utils as schema_utils\n'), ((1885, 1897), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (1895, 1897), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((2422, 2460), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (2443, 2460), True, 'from pay_api.schemas import utils as schema_utils\n'), ((2748, 2760), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (2758, 2760), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((3285, 3326), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""problem"""'], {}), "(rv.json, 'problem')\n", (3306, 3326), True, 'from pay_api.schemas import utils as schema_utils\n'), ((3607, 3619), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (3617, 3619), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((4157, 4195), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (4178, 4195), True, 'from pay_api.schemas import utils as schema_utils\n'), ((4421, 4433), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (4431, 4433), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((4986, 5027), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""problem"""'], {}), "(rv.json, 'problem')\n", (5007, 5027), True, 'from pay_api.schemas import utils as schema_utils\n'), ((5176, 5200), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': '"""staff"""'}), "(role='staff')\n", (5186, 5200), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((5672, 5710), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (5693, 5710), True, 'from pay_api.schemas import utils as schema_utils\n'), ((5914, 5926), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (5924, 5926), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((6398, 6436), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (6419, 6436), True, 'from pay_api.schemas import utils as schema_utils\n'), ((6617, 6629), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (6627, 6629), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((7097, 7135), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (7118, 7135), True, 'from pay_api.schemas import utils as schema_utils\n'), ((7284, 7296), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (7294, 7296), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((7836, 7874), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (7857, 7874), True, 'from pay_api.schemas import utils as schema_utils\n'), ((8139, 8151), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {}), '()\n', (8149, 8151), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((8607, 8645), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (8628, 8645), True, 'from pay_api.schemas import utils as schema_utils\n'), ((8877, 8911), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': 'Role.SYSTEM.value'}), '(role=Role.SYSTEM.value)\n', (8887, 8911), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((9246, 9289), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': 'Role.MANAGE_ACCOUNTS.value'}), '(role=Role.MANAGE_ACCOUNTS.value)\n', (9256, 9289), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((9705, 9739), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': 'Role.EDITOR.value'}), '(role=Role.EDITOR.value)\n', (9715, 9739), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((9975, 10013), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (9996, 10013), True, 'from pay_api.schemas import utils as schema_utils\n'), ((10260, 10303), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': 'Role.MANAGE_ACCOUNTS.value'}), '(role=Role.MANAGE_ACCOUNTS.value)\n', (10270, 10303), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((10677, 10711), 'tests.utilities.base_test.get_claims', 'get_claims', ([], {'role': 'Role.EDITOR.value'}), '(role=Role.EDITOR.value)\n', (10687, 10711), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n'), ((10947, 10985), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (10968, 10985), True, 'from pay_api.schemas import utils as schema_utils\n'), ((2262, 2274), 'datetime.timedelta', 'timedelta', (['(1)'], {}), '(1)\n', (2271, 2274), False, 'from datetime import date, timedelta\n'), ((2479, 2520), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""problem"""'], {}), "(rv.json, 'problem')\n", (2500, 2520), True, 'from pay_api.schemas import utils as schema_utils\n'), ((3125, 3137), 'datetime.timedelta', 'timedelta', (['(1)'], {}), '(1)\n', (3134, 3137), False, 'from datetime import date, timedelta\n'), ((3345, 3383), 'pay_api.schemas.utils.validate', 'schema_utils.validate', (['rv.json', '"""fees"""'], {}), "(rv.json, 'fees')\n", (3366, 3383), True, 'from pay_api.schemas import utils as schema_utils\n'), ((3984, 3996), 'datetime.timedelta', 'timedelta', (['(1)'], {}), '(1)\n', (3993, 3996), False, 'from datetime import date, timedelta\n'), ((4798, 4810), 'datetime.timedelta', 'timedelta', (['(2)'], {}), '(2)\n', (4807, 4810), False, 'from datetime import date, timedelta\n'), ((4826, 4838), 'datetime.timedelta', 'timedelta', (['(1)'], {}), '(1)\n', (4835, 4838), False, 'from datetime import date, timedelta\n'), ((9452, 9563), 'json.dumps', 'json.dumps', (["{'accountFees': [{'applyFilingFees': False, 'serviceFeeCode': 'TRF02',\n    'product': 'BUSINESS'}]}"], {}), "({'accountFees': [{'applyFilingFees': False, 'serviceFeeCode':\n    'TRF02', 'product': 'BUSINESS'}]})\n", (9462, 9563), False, 'import json\n'), ((10474, 10565), 'json.dumps', 'json.dumps', (["{'applyFilingFees': True, 'serviceFeeCode': 'TRF01', 'product': 'BUSINESS'}"], {}), "({'applyFilingFees': True, 'serviceFeeCode': 'TRF01', 'product':\n    'BUSINESS'})\n", (10484, 10565), False, 'import json\n'), ((9071, 9096), 'tests.utilities.base_test.get_gov_account_payload', 'get_gov_account_payload', ([], {}), '()\n', (9094, 9096), False, 'from tests.utilities.base_test import get_claims, get_gov_account_payload, token_header\n')]