# Copyright 2017 Mirantis, Inc.
# All 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.

from django.forms import ValidationError
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import memoized

from manila_ui.api import manila
from manila_ui.dashboards import utils


class CreateShareGroupForm(forms.SelfHandlingForm):
    name = forms.CharField(label=_("Name"), max_length="255", required=True)
    description = forms.CharField(
        label=_("Description"),
        max_length="255",
        widget=forms.Textarea(attrs={"rows": 3}),
        required=False)

    def __init__(self, request, *args, **kwargs):
        super(CreateShareGroupForm, self).__init__(request, *args, **kwargs)
        self.st_field_name_prefix = "share-type-choices-"
        self.fields["source_type"] = forms.ChoiceField(
            label=_("Source Type"),
            widget=forms.Select(attrs={
                "class": "switchable",
                "data-slug": "source",
            }),
            required=False)

        self.fields["snapshot"] = forms.ChoiceField(
            label=_("Use share group snapshot as a source"),
            widget=forms.SelectWidget(attrs={
                "class": "switched",
                "data-switch-on": "source",
                "data-source-snapshot": _("Share Group Snapshot"),
            }),
            required=True)

        if ("snapshot_id" in request.GET or
                kwargs.get("data", {}).get("snapshot")):
            try:
                snapshot = self.get_share_group_snapshot(
                    request,
                    request.GET.get(
                        "snapshot_id",
                        kwargs.get("data", {}).get("snapshot")))
                self.fields["name"].initial = snapshot.name
                self.fields["snapshot"].choices = (
                    (snapshot.id, snapshot.name or snapshot.id),
                )
                try:
                    # Set the share group type from the original share group
                    orig_sg = manila.share_group_get(
                        request, snapshot.share_group_id)
                    self.fields["sgt"].initial = orig_sg.share_group_type_id
                except Exception:
                    pass
                del self.fields["source_type"]
            except Exception:
                exceptions.handle(
                    request,
                    _("Unable to load the specified share group snapshot."))
        else:
            source_type_choices = []
            try:
                snapshot_list = manila.share_group_snapshot_list(request)
                snapshots = [s for s in snapshot_list
                             if s.status == "available"]
                if snapshots:
                    source_type_choices.append(("snapshot", _("Snapshot")))
                    self.fields["snapshot"].choices = (
                        [("", _("Choose a snapshot"))] +
                        [(s.id, s.name or s.id) for s in snapshots]
                    )
                else:
                    del self.fields["snapshot"]
            except Exception:
                exceptions.handle(
                    request,
                    _("Unable to retrieve share group snapshots."))

            if source_type_choices:
                choices = ([('none', _("No source, empty share group"))] +
                           source_type_choices)
                self.fields["source_type"].choices = choices
            else:
                del self.fields["source_type"]

            self.fields["az"] = forms.ChoiceField(
                label=_("Availability Zone"),
                widget=forms.SelectWidget(attrs={
                    "class": "switched",
                    "data-switch-on": "source",
                    "data-source-none": _("Availability Zone"),
                }),
                required=False)

            availability_zones = manila.availability_zone_list(request)
            self.fields["az"].choices = (
                [("", "")] + [(az.name, az.name) for az in availability_zones])

            share_group_types = manila.share_group_type_list(request)
            self.fields["sgt"] = forms.ChoiceField(
                label=_("Share Group Type"),
                widget=forms.fields.SelectWidget(attrs={
                    "class": "switched switchable",
                    "data-switch-on": "source",
                    "data-source-none": _("Share Group Type"),
                    "data-slug": "sgt",
                }),
                required=True)
            self.fields["sgt"].choices = (
                [(utils.transform_dashed_name(sgt.id), sgt.name) for sgt in
                 share_group_types]
            )

            # NOTE(vponomaryov): create separate set of available share types
            # for each of share group types.
            share_types = manila.share_type_list(request)
            for sgt in share_group_types:
                st_choices = (
                    [(st.id, st.name)
                     for st in share_types if st.id in sgt.share_types])
                amount_of_choices = len(st_choices)
                st_field_name = (
                    self.st_field_name_prefix +
                    utils.transform_dashed_name(sgt.id)
                )
                if amount_of_choices < 2:
                    st_field = forms.ChoiceField(
                        label=_("Share Types"),
                        choices=st_choices,
                        widget=forms.fields.SelectWidget(attrs={
                            "class": "switched",
                            "data-switch-on": "sgt",
                            "data-sgt-%s" % utils.transform_dashed_name(
                                sgt.id): _("Share Types (one available)"),
                        }),
                        required=True)
                else:
                    height = min(30 * amount_of_choices, 155)
                    st_field = forms.MultipleChoiceField(
                        label=_("Share Types"),
                        choices=st_choices,
                        widget=forms.fields.widgets.SelectMultiple(attrs={
                            "style": "max-height: %spx;" % height,
                            "class": "switched",
                            "data-switch-on": "sgt",
                            "data-sgt-%s" % utils.transform_dashed_name(
                                sgt.id): _("Share Types (multiple available)"),
                        }),
                        required=False)
                    st_field.initial = st_choices[0]
                self.fields[st_field_name] = st_field

            self.fields["share_network"] = forms.ChoiceField(
                label=_("Share Network"),
                widget=forms.fields.SelectWidget(attrs={
                    "class": "switched",
                    "data-switch-on": "source",
                    "data-source-none": _("Share Network"),
                }),
                required=False)
            share_networks = manila.share_network_list(request)
            self.fields["share_network"].choices = (
                [(sn.id, sn.name or sn.id) for sn in share_networks])

    def clean(self):
        cleaned_data = super(CreateShareGroupForm, self).clean()
        form_errors = list(self.errors)

        for error in form_errors:
            sgt_name = error.split(self.st_field_name_prefix)[-1]
            chosen_sgt = cleaned_data.get("sgt")
            if (error.startswith(self.st_field_name_prefix) and
                    sgt_name != chosen_sgt):
                cleaned_data[error] = "Not set"
                self.errors.pop(error, None)

        source_type = cleaned_data.get("source_type")
        if source_type != "snapshot":
            self.errors.pop("snapshot", None)
            share_group_type = cleaned_data.get("sgt")
            if share_group_type:
                cleaned_data["share_types"] = cleaned_data.get(
                    self.st_field_name_prefix + share_group_type)
                if isinstance(cleaned_data["share_types"], str):
                    cleaned_data["share_types"] = [cleaned_data["share_types"]]
        else:
            self.errors.pop("sgt", None)

        return cleaned_data

    def handle(self, request, data):
        try:
            source_type = data.get('source_type')
            if (data.get("snapshot") and source_type in (None, 'snapshot')):
                snapshot = self.get_share_group_snapshot(
                    request, data["snapshot"])
                snapshot_id = snapshot.id
                source_sg = manila.share_group_get(
                    request, snapshot.share_group_id)
                data['sgt'] = source_sg.share_group_type_id
            else:
                snapshot_id = None

            share_group = manila.share_group_create(
                request,
                name=data['name'],
                description=data['description'],
                share_group_type=utils.transform_dashed_name(data['sgt']),
                share_types=None if snapshot_id else data.get('share_types'),
                share_network=(
                    None if snapshot_id else data.get('share_network')),
                source_share_group_snapshot=snapshot_id,
                availability_zone=None if snapshot_id else data['az'])

            message = _('Creating share group "%s"') % data['name']
            messages.success(request, message)
            return share_group
        except ValidationError as e:
            self.api_error(e.messages[0])
            return False
        except Exception:
            exceptions.handle(request, ignore=True)
            self.api_error(_("Unable to create share group."))
            return False

    @memoized.memoized
    def get_share_group_snapshot(self, request, sg_snapshot_id):
        return manila.share_group_snapshot_get(request, sg_snapshot_id)


class UpdateShareGroupForm(forms.SelfHandlingForm):
    name = forms.CharField(
        max_length="255", label=_("Share Group Name"))
    description = forms.CharField(
        widget=forms.Textarea, label=_("Description"), required=False)

    def handle(self, request, data):
        sg_id = self.initial['share_group_id']
        try:
            manila.share_group_update(
                request, sg_id, data['name'], data['description'])
            message = _('Updating share group "%s"') % data['name']
            messages.success(request, message)
            return True
        except Exception:
            redirect = reverse("horizon:project:share_groups:index")
            exceptions.handle(
                request, _('Unable to update share group.'), redirect=redirect)
            return False
