# coding:utf-8
from django import forms
from django.utils.translation import gettext_lazy as _

from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
from common.utils import validate_ssh_private_key, ssh_pubkey_gen


class AssetCreateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        instance = kwargs.get('instance', None)
        if instance:
            initial = kwargs.get('initial', {})
            initial['tags'] = [t.pk for t in kwargs['instance'].tags.all()]
        super(AssetCreateForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        super(AssetCreateForm, self)._save_m2m()
        tags = self.cleaned_data['tags']
        self.instance.tags.clear()
        self.instance.tags.add(*tuple(tags))

    # def clean(self):
    #     clean_data = super(AssetCreateForm, self).clean()
    #     ip = clean_data.get('ip')
    #     port = clean_data.get('port')
    #     query = Asset.objects.filter(ip=ip, port=port)
    #     if query:
    #         raise forms.ValidationError('this asset has exists.')

    class Meta:
        model = Asset
        tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
        fields = [
            'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups',
            'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no',
            'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags',
        ]
        widgets = {
            'groups': forms.SelectMultiple(attrs={'class': 'select2',
                                                  'data-placeholder': _('Select asset groups')}),
            'tags': forms.SelectMultiple(attrs={'class': 'select2',
                                                'data-placeholder': _('Select asset tags')}),
            'system_users': forms.SelectMultiple(attrs={'class': 'select2',
                                                        'data-placeholder': _('Select asset system users')}),
            'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
        }
        help_texts = {
            'hostname': '* required',
            'ip': '* required',
            'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'),
            'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'),
            'tags': '最多5个标签，单个标签最长8个汉字，按回车确认'
        }


class AssetGroupForm(forms.ModelForm):
    # See AdminUserForm comment same it
    assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
                                            label=_('Asset'),
                                            required=False,
                                            widget=forms.SelectMultiple(
                                                attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
                                            )

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance', None):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
        super(AssetGroupForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        super(AssetGroupForm, self)._save_m2m()
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))

    class Meta:
        model = AssetGroup
        fields = [
            "name", "comment","system_users",
        ]
        widgets = {
            'name' : forms.TextInput(attrs={}),
            'system_users': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}),

        }
        help_texts = {
            'name': '* required',
        }


class IDCForm(forms.ModelForm):
    # See AdminUserForm comment same it
    assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
                                            label=_('Asset'),
                                            required=False,
                                            widget=forms.SelectMultiple(
                                                attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
                                            )

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance'):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
        super(IDCForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        super(IDCForm, self)._save_m2m()
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))

    class Meta:
        model = IDC
        fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'intranet', 'extranet','comment']
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
            'intranet': forms.Textarea(
                attrs={'placeholder': 'IP段之间用逗号隔开，如：192.168.1.0/24,192.168.1.0/24'}),
            'extranet': forms.Textarea(
                attrs={'placeholder': 'IP段之间用逗号隔开，如：201.1.32.1/24,202.2.32.1/24'})
        }
        help_texts = {
            'name': '* required'
        }


class AdminUserForm(forms.ModelForm):
    # Admin user assets define, let user select, save it in form not in view
    assets = forms.ModelMultipleChoiceField(
        queryset=Asset.objects.all(),
        label=_('Asset'),
        required=False,
        widget=forms.SelectMultiple(
            attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
    )
    # Form field name can not start with `_`, so redefine it,
    password = forms.CharField(
        widget=forms.PasswordInput, max_length=100,
        min_length=8, strip=True, required=False,
        help_text=_('If also set private key, use that first'),
    )
    # Need use upload private key file except paste private key content
    private_key_file = forms.FileField(required=False)

    def __init__(self, *args, **kwargs):
        # When update a admin user instance, initial it
        if kwargs.get('instance'):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
        super(AdminUserForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        # Save assets relation with admin user
        super(AdminUserForm, self)._save_m2m()
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))

    def save(self, commit=True):
        # Because we define custom field, so we need rewrite :method: `save`
        admin_user = super(AdminUserForm, self).save(commit=commit)
        password = self.cleaned_data['password']
        private_key = self.cleaned_data['private_key_file']

        if password:
            admin_user.password = password
        if private_key:
            public_key = ssh_pubkey_gen(private_key)
            admin_user.private_key = private_key
            admin_user.public_key = public_key
        admin_user.save()
        return admin_user

    def clean_private_key_file(self):
        private_key_file = self.cleaned_data['private_key_file']
        if private_key_file:
            private_key = private_key_file.read()
            if not validate_ssh_private_key(private_key):
                raise forms.ValidationError(_('Invalid private key'))
            return private_key
        return private_key_file

    def clean(self):
        password = self.cleaned_data['password']
        private_key_file = self.cleaned_data.get('private_key_file', '')

        if not self.instance and not (password or private_key_file):
            raise forms.ValidationError(
                _('Password and private key file must be input one'))

    class Meta:
        model = AdminUser
        fields = ['name', 'username', 'password', 'private_key_file', 'comment']
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
            'username': forms.TextInput(attrs={'placeholder': _('Username')}),
        }
        help_texts = {
            'name': '* required',
            'username': '* required',
        }


class SystemUserForm(forms.ModelForm):
    # Admin user assets define, let user select, save it in form not in view
    auto_generate_key = forms.BooleanField(initial=True, required=False)
    # Form field name can not start with `_`, so redefine it,
    password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True)
    # Need use upload private key file except paste private key content
    private_key_file = forms.FileField(required=False)

    def __init__(self, *args, **kwargs):
        # When update a admin user instance, initial it
        if kwargs.get('instance'):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
            initial['asset_groups'] = kwargs['instance'].asset_groups.all()
        super(SystemUserForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        # Because we define custom field, so we need rewrite :method: `save`
        system_user = super(SystemUserForm, self).save(commit=commit)
        password = self.cleaned_data['password']
        private_key_file = self.cleaned_data['private_key_file']

        if system_user.auth_method == 'P':
            if password:
                system_user.password = password
            print(password)
        # Todo: Validate private key file, and generate public key
        # Todo: Auto generate private key and public key
        if private_key_file:
            system_user.private_key = private_key_file.read().strip()
        system_user.save()
        return self.instance

    # Todo: check valid
    # def clean_private_key_file(self):
    #     if not self.cleaned_data['auto_generate_key']:
    #         if not self.cleaned_data['private_key_file']:
    #             raise forms.ValidationError(_('Private key required'))

    # def clean_password(self):
    #     if self.cleaned_data['auth_method'] == 'P':
    #         if not self.cleaned_data['password']:
    #             raise forms.ValidationError(_('Password required'))
    #     return self.cleaned_data['password']

    # def clean(self):
    #     password = self.cleaned_data['password']
    #     private_key_file = self.cleaned_data.get('private_key_file', '')
    #
    #     if not (password or private_key_file):
    #         raise forms.ValidationError(_('Password and private key file must be input one'))

    class Meta:
        model = SystemUser
        fields = [
            'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'auth_method',
            'auto_push', 'sudo', 'comment', 'shell', 'home', 'uid',
        ]
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
            'username': forms.TextInput(attrs={'placeholder': _('Username')}),
        }
        help_texts = {
            'name': '* required',
            'username': '* required',
            'auto_push': 'Auto push system user to asset',
        }


class AssetTagForm(forms.ModelForm):
    assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
                                            label=_('Asset'),
                                            required=False,
                                            widget=forms.SelectMultiple(
                                                attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
                                            )

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance', None):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].asset_set.all()
        super(AssetTagForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))
        super(AssetTagForm, self)._save_m2m()

    class Meta:
        model = Tag
        fields = [
            "name",
        ]
        widgets = {
            'name' : forms.TextInput(attrs={}),

        }
        help_texts = {
            'name': '* required',
        }


class FileForm(forms.Form):
    file = forms.FileField()
