#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type


DOCUMENTATION = '''
---
module: digital_ocean_domain
short_description: Create/delete a DNS domain in DigitalOcean
description:
     - Create/delete a DNS domain in DigitalOcean.
author: "Michael Gregson (@mgregson)"
options:
  state:
    description:
     - Indicate desired state of the target.
    default: present
    choices: ['present', 'absent']
  id:
    description:
     - Numeric, the droplet id you want to operate on.
    aliases: ['droplet_id']
  name:
    description:
     - String, this is the name of the droplet - must be formatted by hostname rules, or the name of a SSH key, or the name of a domain.
  ip:
    description:
     - An 'A' record for '@' ($ORIGIN) will be created with the value 'ip'.  'ip' is an IP version 4 address.
extends_documentation_fragment:
- community.digitalocean.digital_ocean.documentation

notes:
  - Environment variables DO_OAUTH_TOKEN can be used for the oauth_token.
  - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(oauth_token).
  - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired.

requirements:
  - "python >= 2.6"
'''


EXAMPLES = '''
- name: Create a domain
  digital_ocean_domain:
    state: present
    name: my.digitalocean.domain
    ip: 127.0.0.1

# Create a droplet and corresponding domain
- name: Create a droplet
  digital_ocean:
    state: present
    name: test_droplet
    size_id: 1gb
    region_id: sgp1
    image_id: ubuntu-14-04-x64
  register: test_droplet

- name: Create a corresponding domain
  digital_ocean_domain:
    state: present
    name: "{{ test_droplet.droplet.name }}.my.domain"
    ip: "{{ test_droplet.droplet.ip_address }}"

'''

import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import DigitalOceanHelper
from ansible.module_utils._text import to_native


class DoManager(DigitalOceanHelper, object):
    def __init__(self, module):
        super(DoManager, self).__init__(module)
        self.domain_name = module.params.get('name', None)
        self.domain_ip = module.params.get('ip', None)
        self.domain_id = module.params.get('id', None)

    @staticmethod
    def jsonify(response):
        return response.status_code, response.json

    def all_domains(self):
        resp = self.get('domains/')
        return resp

    def find(self):
        if self.domain_name is None and self.domain_id is None:
            return False

        domains = self.all_domains()
        status, json = self.jsonify(domains)
        for domain in json['domains']:
            if domain['name'] == self.domain_name:
                return True
        return False

    def add(self):
        params = {'name': self.domain_name, 'ip_address': self.domain_ip}
        resp = self.post('domains/', data=params)
        status = resp.status_code
        json = resp.json
        if status == 201:
            return json['domain']
        else:
            return json

    def all_domain_records(self):
        resp = self.get('domains/%s/records/' % self.domain_name)
        return resp.json

    def domain_record(self):
        resp = self.get('domains/%s' % self.domain_name)
        status, json = self.jsonify(resp)
        return json

    def destroy_domain(self):
        resp = self.delete('domains/%s' % self.domain_name)
        status, json = self.jsonify(resp)
        if status == 204:
            return True
        else:
            return json

    def edit_domain_record(self, record):
        params = {'name': '@',
                  'data': self.module.params.get('ip')}
        resp = self.put('domains/%s/records/%s' % (self.domain_name, record['id']), data=params)
        status, json = self.jsonify(resp)

        return json['domain_record']

    def create_domain_record(self):
        params = {'name': '@',
                  'type': 'A',
                  'data': self.module.params.get('ip')}

        resp = self.post('domains/%s/records' % (self.domain_name), data=params)
        status, json = self.jsonify(resp)

        return json['domain_record']


def core(module):
    do_manager = DoManager(module)
    state = module.params.get('state')

    domain = do_manager.find()
    if state == 'present':
        if not domain:
            domain = do_manager.add()
            if 'message' in domain:
                module.fail_json(changed=False, msg=domain['message'])
            else:
                module.exit_json(changed=True, domain=domain)
        else:
            records = do_manager.all_domain_records()
            at_record = None
            for record in records['domain_records']:
                if record['name'] == "@" and record['type'] == 'A':
                    at_record = record

            if not at_record:
                do_manager.create_domain_record()
                module.exit_json(changed=True, domain=do_manager.find())
            elif not at_record['data'] == module.params.get('ip'):
                do_manager.edit_domain_record(at_record)
                module.exit_json(changed=True, domain=do_manager.find())
            else:
                module.exit_json(changed=False, domain=do_manager.domain_record())

    elif state == 'absent':
        if not domain:
            module.exit_json(changed=False, msg="Domain not found")
        else:
            delete_event = do_manager.destroy_domain()
            if not delete_event:
                module.fail_json(changed=False, msg=delete_event['message'])
            else:
                module.exit_json(changed=True, event=None)
        delete_event = do_manager.destroy_domain()
        module.exit_json(changed=delete_event)


def main():
    argument_spec = DigitalOceanHelper.digital_ocean_argument_spec()
    argument_spec.update(
        state=dict(choices=['present', 'absent'], default='present'),
        name=dict(type='str'),
        id=dict(aliases=['droplet_id'], type='int'),
        ip=dict(type='str')
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        required_one_of=(
            ['id', 'name'],
        ),
    )

    try:
        core(module)
    except Exception as e:
        module.fail_json(msg=to_native(e), exception=traceback.format_exc())


if __name__ == '__main__':
    main()
