# Copyright 2017 AT&T Intellectual Property.  All other rights reserved.  #
# 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.
"""Handler resources for Design API endpoints.

NOTICE - THIS API IS DEPRECATED
"""

import falcon
import json
import uuid

import drydock_provisioner.policy as policy
import drydock_provisioner.objects as hd_objects
import drydock_provisioner.error as errors

from .base import StatefulResource


class DesignsResource(StatefulResource):
    """Resource handlers for design collection."""

    def __init__(self, **kwargs):
        super(DesignsResource, self).__init__(**kwargs)

    @policy.ApiEnforcer('physical_provisioner:read_data')
    def on_get(self, req, resp):
        """Method handler for GET requests.

        :param req: Falcon request object
        :param resp: Falcon response object
        """
        state = self.state_manager

        try:
            designs = list(state.designs.keys())

            resp.body = json.dumps(designs)
            resp.status = falcon.HTTP_200
        except Exception as ex:
            self.error(req.context, "Exception raised: %s" % str(ex))
            self.return_error(
                resp,
                falcon.HTTP_500,
                message="Error accessing design list",
                retry=True)

    @policy.ApiEnforcer('physical_provisioner:ingest_data')
    def on_post(self, req, resp):
        """Method handler for POST requests.

        :param req: Falcon request object
        :param resp: Falcon response object
        """
        try:
            json_data = self.req_json(req)
            design = None
            if json_data is not None:
                base_design = json_data.get('base_design_id', None)

                if base_design is not None:
                    base_design = uuid.UUID(base_design)
                    design = hd_objects.SiteDesign(base_design_id=base_design)
            else:
                design = hd_objects.SiteDesign()
            design.assign_id()
            design.create(req.context, self.state_manager)

            resp.body = json.dumps(design.obj_to_simple())
            resp.status = falcon.HTTP_201
        except errors.StateError:
            self.error(req.context, "Error updating persistence")
            self.return_error(
                resp,
                falcon.HTTP_500,
                message="Error updating persistence",
                retry=True)
        except errors.InvalidFormat as fex:
            self.error(req.context, str(fex))
            self.return_error(
                resp, falcon.HTTP_400, message=str(fex), retry=False)


class DesignResource(StatefulResource):
    """Resource Handlers for design singletons."""

    def __init__(self, orchestrator=None, **kwargs):
        super(DesignResource, self).__init__(**kwargs)
        self.authorized_roles = ['user']
        self.orchestrator = orchestrator

    @policy.ApiEnforcer('physical_provisioner:read_data')
    def on_get(self, req, resp, design_id):
        """Method Handler for GET design singleton.

        :param req: Falcon request object
        :param resp: Falcon response object
        :param design_id: UUID of the design resource
        """
        source = req.params.get('source', 'designed')

        try:
            design = None
            if source == 'compiled':
                design = self.orchestrator.get_effective_site(design_id)
            elif source == 'designed':
                design = self.orchestrator.get_described_site(design_id)

            resp.body = json.dumps(design.obj_to_simple())
        except errors.DesignError:
            self.error(req.context, "Design %s not found" % design_id)
            self.return_error(
                resp,
                falcon.HTTP_404,
                message="Design %s not found" % design_id,
                retry=False)


class DesignsPartsResource(StatefulResource):
    def __init__(self, ingester=None, **kwargs):
        super(DesignsPartsResource, self).__init__(**kwargs)
        self.ingester = ingester
        self.authorized_roles = ['user']

        if ingester is None:
            self.error(
                None,
                "DesignsPartsResource requires a configured Ingester instance")
            raise ValueError(
                "DesignsPartsResource requires a configured Ingester instance")

    @policy.ApiEnforcer('physical_provisioner:ingest_data')
    def on_post(self, req, resp, design_id):
        ingester_name = req.params.get('ingester', None)

        if ingester_name is None:
            self.error(
                None,
                "DesignsPartsResource POST requires parameter 'ingester'")
            self.return_error(
                resp,
                falcon.HTTP_400,
                message="POST requires parameter 'ingester'",
                retry=False)
        else:
            try:
                raw_body = req.stream.read(req.content_length or 0)
                if raw_body is not None and len(raw_body) > 0:
                    parsed_items = self.ingester.ingest_data(
                        plugin_name=ingester_name,
                        design_state=self.state_manager,
                        content=raw_body,
                        design_id=design_id,
                        context=req.context)
                    resp.status = falcon.HTTP_201
                    resp.body = json.dumps(
                        [x.obj_to_simple() for x in parsed_items])
                else:
                    self.return_error(
                        resp,
                        falcon.HTTP_400,
                        message="Empty body not supported",
                        retry=False)
            except ValueError:
                self.return_error(
                    resp,
                    falcon.HTTP_500,
                    message="Error processing input",
                    retry=False)
            except LookupError:
                self.return_error(
                    resp,
                    falcon.HTTP_400,
                    message="Ingester %s not registered" % ingester_name,
                    retry=False)

    @policy.ApiEnforcer('physical_provisioner:ingest_data')
    def on_get(self, req, resp, design_id):
        try:
            design = self.state_manager.get_design(design_id)
        except errors.DesignError:
            self.return_error(
                resp,
                falcon.HTTP_404,
                message="Design %s nout found" % design_id,
                retry=False)

        part_catalog = []

        site = design.get_site()

        part_catalog.append({'kind': 'Region', 'key': site.get_id()})

        part_catalog.extend([{
            'kind': 'Network',
            'key': n.get_id()
        } for n in design.networks])

        part_catalog.extend([{
            'kind': 'NetworkLink',
            'key': link.get_id()
        } for link in design.network_links])

        part_catalog.extend([{
            'kind': 'HostProfile',
            'key': p.get_id()
        } for p in design.host_profiles])

        part_catalog.extend([{
            'kind': 'HardwareProfile',
            'key': p.get_id()
        } for p in design.hardware_profiles])

        part_catalog.extend([{
            'kind': 'BaremetalNode',
            'key': n.get_id()
        } for n in design.baremetal_nodes])

        resp.body = json.dumps(part_catalog)
        resp.status = falcon.HTTP_200
        return


class DesignsPartsKindsResource(StatefulResource):
    def __init__(self, **kwargs):
        super(DesignsPartsKindsResource, self).__init__(**kwargs)
        self.authorized_roles = ['user']

    @policy.ApiEnforcer('physical_provisioner:read_data')
    def on_get(self, req, resp, design_id, kind):

        resp.status = falcon.HTTP_200


class DesignsPartResource(StatefulResource):
    def __init__(self, orchestrator=None, **kwargs):
        super(DesignsPartResource, self).__init__(**kwargs)
        self.authorized_roles = ['user']
        self.orchestrator = orchestrator

    @policy.ApiEnforcer('physical_provisioner:read_data')
    def on_get(self, req, resp, design_id, kind, name):
        source = req.params.get('source', 'designed')

        try:
            design = None
            if source == 'compiled':
                design = self.orchestrator.get_effective_site(design_id)
            elif source == 'designed':
                design = self.orchestrator.get_described_site(design_id)

            part = None
            if kind == 'Site':
                part = design.get_site()
            elif kind == 'Network':
                part = design.get_network(name)
            elif kind == 'NetworkLink':
                part = design.get_network_link(name)
            elif kind == 'HardwareProfile':
                part = design.get_hardware_profile(name)
            elif kind == 'HostProfile':
                part = design.get_host_profile(name)
            elif kind == 'BaremetalNode':
                part = design.get_baremetal_node(name)
            else:
                self.error(req.context, "Kind %s unknown" % kind)
                self.return_error(
                    resp,
                    falcon.HTTP_404,
                    message="Kind %s unknown" % kind,
                    retry=False)
                return

            resp.body = json.dumps(part.obj_to_simple())
        except errors.DesignError as dex:
            self.error(req.context, str(dex))
            self.return_error(
                resp, falcon.HTTP_404, message=str(dex), retry=False)
        except Exception as exc:
            self.error(req.context, str(exc))
            self.return_error(
                resp.falcon.HTTP_500, message=str(exc), retry=False)