from django import forms
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils.translation import gettext as _
from eveuniverse.models import EveGroup, EveMarketGroup, EveSolarSystem, EveType

from buybackprogram.models import (
    HangarDivision,
    Location,
    Owner,
    Program,
    ReverseProgram,
    UserSettings,
    WalletDivision,
)


class ProgramForm(forms.ModelForm):
    # specify the name of model to use
    class Meta:
        model = Program
        fields = "__all__"
        labels = {
            "price_dencity_modifier": "Price density modifier",
            "price_dencity_treshold": "Price density threshold",
            "price_dencity_tax": "Price density tax",
            "wallet": "Funding Wallet",
        }

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop("user", None)

        super(ProgramForm, self).__init__(*args, **kwargs)
        self.fields["owner"].queryset = Owner.objects.filter(user=self.user)
        self.fields["location"].queryset = Location.objects.filter(
            owner__user=self.user
        )
        if "wallet" in self.fields:
            self.fields["wallet"].queryset = WalletDivision.objects.filter(
                owner__user=self.user
            )


class ProgramItemForm(forms.Form):
    item_type = forms.ModelChoiceField(
        queryset=EveType.objects.none(),
        label="Item type",
        help_text="Add the name of item which you want to determine an tax on. Once you start typing, we offer suggestions",
        empty_label=None,
    )
    item_tax = forms.IntegerField(
        label="Tax amount",
        initial=0,
        validators=[MaxValueValidator(100), MinValueValidator(-100)],
        help_text="Set an tax on the item. If program default tax is defined this tax will be added on top of the program tax. If program does not allow all items this tax is used to calculate the tax for the product.",
    )
    disallow_item = forms.BooleanField(
        label="Disallow item in this program",
        help_text="If you want to prevent any prices to be given for this item in this program you can check this box.",
        required=False,
    )

    def __init__(self, *args, **kwargs):
        value = kwargs.pop("value", None)

        super(ProgramItemForm, self).__init__(*args, **kwargs)

        if value is not None:
            self.fields["item_type"].queryset = EveType.objects.filter(
                pk=value,
                published=True,
            ).exclude(eve_group__eve_category__id=9)


class StaticItemPriceForm(forms.Form):
    item_type = forms.ModelChoiceField(
        queryset=EveType.objects.none(),
        label="Item type",
        help_text="Start typing to search for an item.",
        empty_label=None,
    )
    price = forms.DecimalField(
        label="Static Buy Price (ISK)",
        max_digits=20,
        decimal_places=2,
        min_value=0,
    )

    def __init__(self, *args, **kwargs):
        value = kwargs.pop("value", None)
        super(StaticItemPriceForm, self).__init__(*args, **kwargs)
        if value is not None:
            self.fields["item_type"].queryset = EveType.objects.filter(
                pk=value,
                published=True,
            ).exclude(eve_group__eve_category__id=9)


class ProgramMarketGroupForm(forms.Form):
    marketgroup = forms.ModelChoiceField(
        queryset=EveMarketGroup.objects.none(),
        label="Item type",
        help_text="Add the name of item which you want to determine an tax on. Once you start typing, we offer suggestions",
        empty_label=None,
    )
    item_tax = forms.IntegerField(
        label="Tax amount",
        initial=0,
        validators=[MaxValueValidator(100), MinValueValidator(-100)],
        help_text="Set an tax on the item. If program default tax is defined this tax will be added on top of the program tax. If program does not allow all items this tax is used to calculate the tax for the product.",
    )
    disallow_item = forms.BooleanField(
        label="Disallow item in this program",
        help_text="If you want to prevent any prices to be given for this item in this program you can check this box.",
        required=False,
    )

    def __init__(self, *args, **kwargs):
        value = kwargs.pop("value", None)

        super(ProgramMarketGroupForm, self).__init__(*args, **kwargs)

        if value is not None:
            self.fields["marketgroup"].queryset = EveMarketGroup.objects.filter(
                pk=value,
            )


class LocationForm(forms.Form):
    eve_solar_system = forms.ModelChoiceField(
        queryset=EveSolarSystem.objects.none(),
        required=False,
        label="Solar system",
        help_text="Select solar system name. Start typing and we will give you suggestions.",
        empty_label=None,
    )
    name = forms.CharField(
        label="Location Name",
        help_text="Station/structure name of location flag. This does not have to match ingame name. May also be a custom name such as Region: Forge if you want to accept at all locations within Forge.",
        max_length=32,
    )

    structure_id = forms.IntegerField(
        required=False,
        label="Structure/station ID",
        help_text="The ingame ID for the structure you wish to accept the contracts at. <strong>If left empty the program statistics page will not track if the contract is actually made at the correct structure or not.</strong>",
    )

    def __init__(self, *args, **kwargs):
        value = kwargs.pop("value", None)
        self.user = kwargs.pop("user", None)

        super(LocationForm, self).__init__(*args, **kwargs)

        if value is not None:
            self.fields["eve_solar_system"].queryset = EveSolarSystem.objects.filter(
                pk=value,
            )


class CalculatorForm(forms.Form):
    items = forms.CharField(
        widget=forms.Textarea,
        label="Items",
        help_text="Copy and paste the item data from your inventory. Item types not in this buyback program will be ignored",
    )
    donation = forms.IntegerField(
        label="Donation %",
        initial=0,
        help_text="You can set a optional donation percentage on your contract",
        validators=[MaxValueValidator(100), MinValueValidator(0)],
    )
    additional_notes = forms.CharField(
        label="Additional Notes",
        help_text="You can set additional notes for your contract in here",
        required=False,  # Make sure it's not required
    )


class UserSettingsForm(forms.ModelForm):
    """
    User settings form
    """

    disable_notifications = forms.BooleanField(
        initial=False,
        required=False,
        label=_(
            "Disable notifications. "
            "(Auth and Discord, if a relevant module is installed)"
        ),
    )

    class Meta:  # pylint: disable=too-few-public-methods
        """
        Meta definitions
        """

        model = UserSettings
        fields = ["disable_notifications"]


class AddWatchlistForm(forms.Form):
    item_type = forms.ModelChoiceField(
        queryset=EveType.objects.none(),
        label="Item type",
        help_text="Start typing to search for an item (Optional).",
        required=False,
        empty_label=None,
    )
    eve_group = forms.ModelChoiceField(
        queryset=EveGroup.objects.none(),
        label="EVE Group",
        help_text="Start typing to search for an item group (Optional).",
        required=False,
        empty_label=None,
    )

    def __init__(self, *args, **kwargs):
        # Extract both values safely
        item_val = kwargs.pop("item_value", None)
        group_val = kwargs.pop("group_value", None)

        super(AddWatchlistForm, self).__init__(*args, **kwargs)

        # Populate the querysets if a POST request sent data
        if item_val is not None:
            self.fields["item_type"].queryset = EveType.objects.filter(
                pk=item_val, published=True
            )

        if group_val is not None:
            self.fields["eve_group"].queryset = EveGroup.objects.filter(pk=group_val)

    def clean(self):
        cleaned_data = super().clean()
        item_type = cleaned_data.get("item_type")
        eve_group = cleaned_data.get("eve_group")

        if not item_type and not eve_group:
            raise forms.ValidationError(
                "You must specify either an Item Type or a Group."
            )
        if item_type and eve_group:
            raise forms.ValidationError(
                "Please specify either an Item Type OR a Group, not both in a single entry."
            )

        return cleaned_data


class ReverseProgramForm(forms.ModelForm):
    class Meta:
        model = ReverseProgram
        fields = "__all__"
        labels = {
            "markup": "Sell markup %",
            "is_public": "Public program",
            "is_corporation": "Use corporation as contract issuer",
        }

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop("user", None)
        super(ReverseProgramForm, self).__init__(*args, **kwargs)

        is_admin = self.user and self.user.has_perm(
            "buybackprogram.manage_all_programs"
        )

        if is_admin:
            self.fields["owner"].queryset = Owner.objects.all()
            self.fields["location"].queryset = Location.objects.all()
            self.fields["hangar_division"].queryset = HangarDivision.objects.all()
        else:
            self.fields["owner"].queryset = Owner.objects.filter(user=self.user)
            self.fields["location"].queryset = Location.objects.filter(
                owner__user=self.user
            )
            self.fields["hangar_division"].queryset = HangarDivision.objects.filter(
                owner__user=self.user
            )


class ReverseCalculatorForm(forms.Form):
    items = forms.CharField(
        widget=forms.Textarea,
        label="Items",
        help_text="Copy and paste the items you want to buy from your inventory or a market list. Quantities will be checked against available stock.",
    )
    additional_notes = forms.CharField(
        label="Additional Notes",
        help_text="Optional notes for the program owner.",
        required=False,
    )
