# 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.

import copy

from openstack import exceptions
from openstack.tests.unit import base


zone_dict = {
    'name': 'example.net.',
    'type': 'PRIMARY',
    'email': 'test@example.net',
    'description': 'Example zone',
    'ttl': 3600,
    'id': '1'
}


class ZoneTestWrapper:

    def __init__(self, ut, attrs):
        self.remote_res = attrs
        self.ut = ut

    def get_create_response_json(self):
        return self.remote_res

    def get_get_response_json(self):
        return self.remote_res

    def __getitem__(self, key):
        """Dict access to be able to access properties easily
        """
        return self.remote_res[key]

    def cmp(self, other):
        ut = self.ut
        me = self.remote_res

        for k, v in me.items():
            # Go over known attributes. We might of course compare others,
            # but not necessary here
            ut.assertEqual(v, other[k])


class TestZone(base.TestCase):

    def setUp(self):
        super(TestZone, self).setUp()
        self.use_designate()

    def test_create_zone(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        self.register_uris([
            dict(method='POST',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones']),
                 json=fake_zone.get_create_response_json(),
                 validate=dict(json={
                     'description': zone_dict['description'],
                     'email': zone_dict['email'],
                     'name': zone_dict['name'],
                     'ttl': zone_dict['ttl'],
                     'type': 'PRIMARY'
                 }))
        ])
        z = self.cloud.create_zone(
            name=zone_dict['name'],
            zone_type=zone_dict['type'],
            email=zone_dict['email'],
            description=zone_dict['description'],
            ttl=zone_dict['ttl'],
            masters=None)
        fake_zone.cmp(z)
        self.assert_calls()

    def test_create_zone_exception(self):
        self.register_uris([
            dict(method='POST',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones']),
                 status_code=500)
        ])

        self.assertRaises(
            exceptions.SDKException,
            self.cloud.create_zone,
            'example.net.'
        )
        self.assert_calls()

    def test_update_zone(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        new_ttl = 7200
        updated_zone_dict = copy.copy(zone_dict)
        updated_zone_dict['ttl'] = new_ttl
        updated_zone = ZoneTestWrapper(self, updated_zone_dict)
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones', fake_zone['id']]),
                 json=fake_zone.get_get_response_json()),
            dict(method='PATCH',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones', fake_zone['id']]),
                 json=updated_zone.get_get_response_json(),
                 validate=dict(json={"ttl": new_ttl}))
        ])
        z = self.cloud.update_zone(fake_zone['id'], ttl=new_ttl)
        updated_zone.cmp(z)
        self.assert_calls()

    def test_delete_zone(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones', fake_zone['id']]),
                 json=fake_zone.get_get_response_json()),
            dict(method='DELETE',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones', fake_zone['id']]),
                 status_code=202)
        ])
        self.assertTrue(self.cloud.delete_zone(fake_zone['id']))
        self.assert_calls()

    def test_get_zone_by_id(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones', fake_zone['id']]),
                 json=fake_zone.get_get_response_json())
        ])
        res = self.cloud.get_zone(fake_zone['id'])

        fake_zone.cmp(res)
        self.assert_calls()

    def test_get_zone_by_name(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public',
                     append=['v2', 'zones', fake_zone['name']]),
                 status_code=404),
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones'],
                     qs_elements=[
                        'name={name}'.format(name=fake_zone['name'])]),
                 json={"zones": [fake_zone.get_get_response_json()]})
        ])
        res = self.cloud.get_zone(fake_zone['name'])
        fake_zone.cmp(res)
        self.assert_calls()

    def test_get_zone_not_found_returns_false(self):
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public',
                     append=['v2', 'zones', 'nonexistingzone.net.']),
                 status_code=404),
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public', append=['v2', 'zones'],
                     qs_elements=['name=nonexistingzone.net.']),
                 json={"zones": []})
        ])
        zone = self.cloud.get_zone('nonexistingzone.net.')
        self.assertFalse(zone)
        self.assert_calls()

    def test_list_zones(self):
        fake_zone = ZoneTestWrapper(self, zone_dict)
        self.register_uris([
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public',
                     append=['v2', 'zones']),
                 json={'zones': [fake_zone.get_get_response_json()],
                       'links': {
                           'next': self.get_mock_url(
                               'dns', 'public',
                               append=['v2', 'zones/'],
                               qs_elements=['limit=1', 'marker=asd']),
                           'self': self.get_mock_url(
                               'dns', 'public',
                               append=['v2', 'zones/'],
                               qs_elements=['limit=1'])},
                       'metadata':{'total_count': 2}}),
            dict(method='GET',
                 uri=self.get_mock_url(
                     'dns', 'public',
                     append=['v2', 'zones/'],
                     qs_elements=[
                        'limit=1', 'marker=asd']),
                 json={'zones': [fake_zone.get_get_response_json()]}),
        ])
        res = self.cloud.list_zones()

        # updated_rs.cmp(res)
        self.assertEqual(2, len(res))
        self.assert_calls()
