import datetime

import requests
from allauth.socialaccount.providers.oauth2.views import (
    OAuth2Adapter,
    OAuth2CallbackView,
    OAuth2LoginView,
)
from django.http import HttpResponse
from django.shortcuts import redirect, render, reverse
from django.views.generic import ListView
from django.views.generic.edit import FormView

from .forms import OpponentForm, PreferencesForm
from .models import Opponent, Preferences
from .provider import TeamsnapProvider
from .utils import get_teamsnap_client


class TeamsnapAdapter(OAuth2Adapter):
    provider_id = TeamsnapProvider.id

    # Fetched programmatically, must be reachable from container
    access_token_url = "{}/oauth/token/".format("https://auth.teamsnap.com")
    profile_url = "{}/me/".format("https://api.teamsnap.com/v3/")

    # Accessed by the user browser, must be reachable by the host
    authorize_url = "{}/oauth/authorize/".format("https://auth.teamsnap.com/")

    # NOTE: trailing slashes in URLs are important, don't miss it

    def complete_login(self, request, app, token, **kwargs):
        headers = {"Authorization": f"Bearer {token.token}"}
        resp = requests.get(self.profile_url, headers=headers)
        j = resp.json()
        if j.get("collection", {}).get("items"):
            extra_data = {
                i["name"]: i["value"] for i in j["collection"]["items"][0]["data"]
            }
        return self.get_provider().sociallogin_from_response(request, extra_data)

    def populate_user(self, request, sociallogin, data):
        user = super().populate_user(request, sociallogin, data)
        user.username = user.email
        return user


oauth2_login = OAuth2LoginView.adapter_view(TeamsnapAdapter)
oauth2_callback = OAuth2CallbackView.adapter_view(TeamsnapAdapter)


class PreferencesFormView(FormView):
    template_name = "preferences.html"
    form_class = PreferencesForm
    success_url = "/"

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        if form.data["user"] == str(self.request.user.id):
            form.save()
            return super().form_valid(form)
        else:
            return super().form_invalid(form)

    def get_initial(self):
        """
        Returns the initial data to use for forms on this view.
        """
        initial = super().get_initial()

        initial["user"] = self.request.user
        # initial['managed_team_id']

        return initial

    def get_form(self):
        """
        Returns the initial data to use for forms on this view.
        """
        import pyteamsnap

        ts_account = self.request.user.socialaccount_set.first()
        ts_token = ts_account.socialtoken_set.first()
        # ts_token =
        ts = pyteamsnap.TeamSnap(token=ts_token)

        me = pyteamsnap.api.Me(ts)

        teams = [
            (id, pyteamsnap.api.Team.get(ts, id=id))
            for id in me.data["managed_team_ids"]
        ]

        try:
            contact = Preferences.objects.get(user=self.request.user)
            form = PreferencesForm(instance=contact, **self.get_form_kwargs())
        except Preferences.DoesNotExist:
            form = super().get_form(self.form_class)

        choices = [
            (id, f"{team.data['name']} ({team.data['season_name']})")
            for id, team in teams
        ]
        form.fields["managed_team_id"].widget.choices = choices

        return form


def schedule_view(request, team_id=None):
    if not team_id:
        return redirect(
            "teamsnap_schedule",
            team_id=request.user.teamsnap_preferences.managed_team_id,
        )
    client = get_teamsnap_client(request)
    no_past = bool(request.GET.get("no_past", 0))
    games_only = bool(request.GET.get("games_only", 0))
    from pyteamsnap.objects import Event

    ts_events = Event.search(client, team_id=team_id)
    if no_past:
        ts_events = [
            e
            for e in ts_events
            if e.data["start_date"] > datetime.datetime.now(datetime.timezone.utc)
        ]
    if games_only:
        ts_events = [e for e in ts_events if e.data["is_game"]]
    ts_events = {e.data["id"]: e for e in ts_events}

    pass
    return render(
        request,
        "schedule.html",
        context={"events": ts_events.values(), "team_id": team_id},
    )


def view_event(request, event_id, team_id=None):
    if not team_id:
        return redirect(
            "teamsnap_event", team_id=request.user.teamsnap_preferences.managed_team_id
        )

    from pyteamsnap.objects import (
        AvailabilitySummary,
        Event,
        EventLineup,
        EventLineupEntry,
        Member,
    )

    client = get_teamsnap_client(request)
    ts_bulkload = client.bulk_load(
        team_id=team_id,
        types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member],
        event__id=event_id,
    )
    ts_event = [i for i in ts_bulkload if isinstance(i, Event)][0]
    ts_availability_summary = [
        i
        for i in ts_bulkload
        if isinstance(i, AvailabilitySummary) and i.data["event_id"] == event_id
    ][0]
    ts_lineup_entries = [
        i
        for i in ts_bulkload
        if isinstance(i, EventLineupEntry) and i.data["event_id"] == event_id
    ]

    return render(
        request,
        "event/view_event.html",
        context={
            "availability_summary": ts_availability_summary,
            "event": ts_event,
            "availablities": [],
            "lineup_entries": ts_lineup_entries,
        },
    )


def multi_lineup_choose(request, team_id):
    from django.forms import formset_factory

    from pyteamsnap.objects import Event

    from .forms import EventChooseForm

    client = get_teamsnap_client(request)

    if request.method == "POST":
        ts_events = Event.search(client, team_id=team_id)
        EventChooseFormset = formset_factory(EventChooseForm)
        formset = EventChooseFormset(request.POST)
        choices = [(e.data["id"], e.data["formatted_title"]) for e in ts_events]

        for form in formset:
            form.fields["event_id"].choices = choices

        if formset.is_valid():
            event_ids = [f.cleaned_data["event_id"] for f in formset]
        else:
            event_ids = request.GET.get("event_ids").split(",")
        EventChooseFormset = formset_factory(EventChooseForm)
        formset = EventChooseFormset(request.POST)

        return redirect(
            "teamsnap_edit_lineup",
            team_id=team_id,
            event_ids=",".join(event_ids),
        )
    elif not request.GET.get("num"):
        return HttpResponse(500)
    else:
        num = int(request.GET.get("num"))
    TEAM_ID = team_id

    ts_events = Event.search(client, team_id=TEAM_ID)
    ts_events = {e.data["id"]: e for e in ts_events}

    EventChooseFormset = formset_factory(EventChooseForm, extra=num)
    formset = EventChooseFormset()

    choices = [(id, e.data["formatted_title"]) for id, e in ts_events.items()]

    for form in formset:
        form.fields["event_id"].choices = choices

    pass
    return render(
        request,
        "lineup/multiple_choose.html",
        context={"formset": formset, "team_id": team_id},
    )


class OpponentFormView(FormView):
    pk_url_kwarg = "opponent_id"
    template_name = "opponent.html"
    form_class = OpponentForm

    def get_success_url(self):
        team_id = self.kwargs.get("team_id")
        return reverse("teamsnap_opponents", kwargs={"team_id": team_id})

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        import pyteamsnap

        ts_client = get_teamsnap_client(self.request)
        user = pyteamsnap.api.Me(ts_client)
        team_id = int(self.kwargs.get("team_id"))
        opponent_id = int(self.kwargs.get("opponent_id"))
        opponent = pyteamsnap.api.Opponent.get(ts_client, opponent_id)
        if (
            team_id in user.data["managed_team_ids"]
            and opponent.data["team_id"] == team_id
        ):
            form.save()
            return super().form_valid(form)
        else:
            return super().form_invalid(form)

    def get_form(self):
        """
        Returns the initial data to use for forms on this view.
        """

        try:
            opponent, _ = Opponent.objects.get_or_create(
                id=self.kwargs.get("opponent_id")
            )
            form = OpponentForm(instance=opponent, **self.get_form_kwargs())

        except Opponent.DoesNotExist:
            form = super().get_form(self.form_class)
            # form.widgets['id'] = forms.HiddenInput()

        return form

    def get_context_data(self, **kwargs):
        import pyteamsnap.objects

        ts_client = get_teamsnap_client(self.request)
        context = super().get_context_data(**kwargs)
        opponent = pyteamsnap.objects.Opponent.get(
            ts_client, self.kwargs.get("opponent_id")
        )
        context["opponent"] = opponent
        return context


class Opponents(ListView):
    model = Opponent
    template_name = "opponents.html"
    pass

    def get_queryset(self):
        from pyteamsnap.objects import Opponent as TsOpponent

        ts_client = get_teamsnap_client(self.request)
        team_id = self.kwargs.get("team_id")
        ts_opponents = TsOpponent.search(ts_client, team_id=team_id)
        ts_opponents.sort(key=lambda t: t.data.get("name"))
        opponents = []
        for opponent in ts_opponents:
            o, _ = Opponent.objects.get_or_create(id=opponent.data["id"])
            opponents.append((opponent, o))

        return opponents

    def get_context_data(self, **kwargs):
        team_id = self.kwargs.get("team_id")
        context = super().get_context_data(**kwargs)
        context["team_id"] = team_id
        return context
