"""
API views – migrated from app/Http/Controllers/ (API routes)

All routes are protected by:
  - IsAuthenticated  (auth:sanctum → AdminTokenAuthentication)
  - IsApiUser        (limit2apiusers middleware → DRF permission class)

Mapping:
  GET/PUT/DELETE /api/res     → RealEstateView (combined)
  GET/PUT        /api/reus   → REUView (combined)
  GET/PUT        /api/users  → UserView (combined)
  GET    /api/mietvs/{reid}   → MietVByREIDView
  PUT    /api/mietvs          → MietVStoreOrUpdateView
  PUT    /api/refverbrrahmen  → RefVerRahmenStoreOrUpdateView
  PUT    /api/refverbrdaten   → RefVerDatenStoreOrUpdateView
  PUT    /api/verbrrahmen     → VerRahmenStoreOrUpdateView
  POST   /api/verbrdaten      → VerDatenStoreView
  PUT    /api/verbrdaten      → VerDatenStoreOrUpdateView
  GET    /api/me              → MeView
  POST   /api/me/tokencreate  → TokenCreateView
  GET    /api/anmeldungen     → AnmeldungenView  (?seit_id=N, inkrementell)
  GET    /api/besuche         → BesucheView      (?seit_id=N, inkrementell)
"""

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from app_admin.authentication import AdminTokenAuthentication
from app_admin.authentication import AdminTokenAuthentication
from rest_framework.permissions import IsAuthenticated

from app_nutzer.models import User, ReuMietV, ReuEigentuemer, NutzerAnmeldung, NutzerBesuch
from app_real_estate.models import RealEstate, RealEstateUnit

from app_verbrauch.models import (
    VISysVerbrauchRahmen, VISysVerbrauchsDS,
    VISysRefVerbrauchRahmen, VISysRefVerbrauchsDS,
)
from .serializers import (
    UserApiSerializer, 
    # ApiUserSerializer,
    RealEstateSerializer, RealEstateUnitSerializer, ReuMietVSerializer,
    ReuEigentuemerSerializer,
    VISysRefVerbrauchRahmenSerializer, VISysRefVerbrauchsDSSerializer,
    VISysVerbrauchRahmenSerializer, VISysVerbrauchsDSSerializer,
)
# from .permissions import IsApiUser
from django.db import connection

from core.services.nutzungsverhaeltnisse import (
    ART_EIGENTUEMER, ART_MIETER, ueberlappende_verhaeltnisse,
)


def _pruefe_ueberlappung(reuid, von, bis, art, quell_id):
    """Ueberlappende Nutzungsverhaeltnisse ablehnen (xin, Arbeitspaket A).

    Geprueft wird gegen Nutzungsperioden, nicht gegen Mietvertraege -- sonst
    bleibt im WEG-Fall der Eigentuemer-Nutzer unsichtbar und Ueberlappungen
    Eigentuemer <-> Mieter kaemen durch.

    Abgelehnt wird das VERHAELTNIS, nicht der Nutzer: eine Person darf
    gleichzeitig in mehreren Einheiten stehen.
    """
    kollisionen = ueberlappende_verhaeltnisse(reuid, von, bis, ausser=(art, quell_id))
    if not kollisionen:
        return None

    k = kollisionen[0]
    rolle = 'Eigentumsverhaeltnis' if k.art == ART_EIGENTUEMER else 'Mietverhaeltnis'
    ende = k.gueltig_bis.isoformat() if k.gueltig_bis else 'ohne Enddatum'
    return Response(
        {
            'detail': (
                f'REU {reuid} hat bereits {rolle} {k.quell_id} '
                f'(Person {k.personen_id}, ab {k.gueltig_von} {ende}).'
            ),
            'konflikte': [
                {
                    'art': x.art,
                    'quell_id': x.quell_id,
                    'personen_id': x.personen_id,
                    'gueltig_von': x.gueltig_von,
                    'gueltig_bis': x.gueltig_bis,
                }
                for x in kollisionen
            ],
        },
        status=status.HTTP_409_CONFLICT,
    )


# Shared permission set for all protected API routes
API_PERMISSIONS = [IsAuthenticated ] # ApiUserSerializer


def _first_error_message(errors):
    """Erste Fehlermeldung aus Serializer-Fehlern ziehen – auch bei many=True.

    ListSerializer.errors ist eine Liste mit einem Eintrag je Element und einem
    leeren Dict fuer gueltige Elemente; bei ungueltigem Payload-Typ dagegen ein
    Dict. Ein hartes errors[0] laeuft deshalb in IndexError/KeyError, sobald der
    Fehler nicht im ersten Datensatz steckt -> HTTP 500 statt 400.
    """
    if isinstance(errors, dict):
        for field, messages in errors.items():
            detail = messages[0] if isinstance(messages, (list, tuple)) and messages else messages
            return f'{field}: {detail}'
        return 'Validation error'
    if isinstance(errors, (list, tuple)):
        for index, item in enumerate(errors):
            if not item:
                continue
            if isinstance(item, dict):
                return f'Datensatz {index}: {_first_error_message(item)}'
            if isinstance(item, (list, tuple)):
                return f'Datensatz {index}: {item[0]}'
            return f'Datensatz {index}: {item}'
    return 'Validation error'


# ---------------------------------------------------------------------------
# RealEstate – migrated from RealEstateController
# ---------------------------------------------------------------------------

class RealEstateView(APIView):
    """
    GET    /api/res – list all real estates.
    PUT    /api/res – create or update real estate.
    DELETE /api/res – delete ALL data cascade (use with caution).
    Migrated from RealEstateController.
    """
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request):
        qs = RealEstate.objects.all()
        return Response(RealEstateSerializer(qs, many=True).data)

    def put(self, request):
        serializer = RealEstateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(list(serializer.errors.values())[0], status=status.HTTP_400_BAD_REQUEST)
        data = serializer.validated_data
        obj, _ = RealEstate.objects.update_or_create(REID=data['REID'], defaults=data)
        return Response(RealEstateSerializer(obj).data)

    def delete(self, request):
        VISysVerbrauchsDS.objects.all().delete()
        VISysVerbrauchRahmen.objects.all().delete()
        VISysRefVerbrauchsDS.objects.all().delete()
        VISysRefVerbrauchRahmen.objects.all().delete()
        ReuMietV.objects.all().delete()
        RealEstateUnit.objects.all().delete()
        User.objects.all().delete()
        count = RealEstate.objects.all().delete()
        return Response({'deleted': count})


# ---------------------------------------------------------------------------
# RealEstateUnit – migrated from REUController
# ---------------------------------------------------------------------------

class REUView(APIView):
    """
    GET /api/reus – list all units.
    PUT /api/reus – bulk create or update units (accepts list).
    Migrated from REUController.
    """
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request):
        qs = RealEstateUnit.objects.all()
        return Response(RealEstateUnitSerializer(qs, many=True).data)

    def put(self, request):
        data = request.data if isinstance(request.data, list) else [request.data]
        serializer = RealEstateUnitSerializer(data=data, many=True)
        if not serializer.is_valid():
            return Response(_first_error_message(serializer.errors), status=status.HTTP_400_BAD_REQUEST)
        count = 0
        for item in serializer.validated_data:
            RealEstateUnit.objects.update_or_create(REUID=item['REUID'], defaults=item)
            count += 1
        return Response(count, status=status.HTTP_201_CREATED)


# ---------------------------------------------------------------------------
# User – migrated from UserController (API methods)
# ---------------------------------------------------------------------------

class UserView(APIView):
    """
    GET /api/users – list all users.
    PUT /api/users – create or update user.
    Migrated from UserController API methods.
    """
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request):
        qs = User.objects.all()
        return Response(UserApiSerializer(qs, many=True).data)

    def put(self, request):
        import secrets
        data = request.data.copy()
        if not data.get('password'):
            data['password'] = secrets.token_hex(16)

        try:
            user = User.objects.get(PersonenID=data.get('PersonenID'))
            serializer = UserApiSerializer(user, data=data, partial=True)
        except User.DoesNotExist:
            serializer = UserApiSerializer(data=data)

        if not serializer.is_valid():
            first_error = list(serializer.errors.values())[0]
            return Response(first_error, status=status.HTTP_400_BAD_REQUEST)

        obj = serializer.save()
        return Response(UserApiSerializer(obj).data)


# ---------------------------------------------------------------------------
# ReuMietV – migrated from MietVController
# ---------------------------------------------------------------------------

class MietVByREIDView(APIView):
    """GET /api/mietvs/{reid} – get all tenancies for a property."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request, reid):
        with connection.cursor() as cursor:
            cursor.execute("""
                SELECT rmv.*, reu.REID, reu.REUDesc, re.Street, re.HouseNumber, re.PostalCode, re.City
                FROM reu_miet_v_s rmv
                LEFT JOIN real_estate_units reu ON reu.REUID = rmv.REUID
                LEFT JOIN real_estates re ON re.REID = reu.REID
                WHERE reu.REID = %s
            """, [reid])
            columns = [col[0] for col in cursor.description]
            rows = cursor.fetchall()
        result = [dict(zip(columns, row)) for row in rows]
        return Response(result)


class MietVStoreOrUpdateView(APIView):
    """PUT /api/mietvs – create or update tenancy."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def put(self, request):
        serializer = ReuMietVSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(list(serializer.errors.values())[0], status=status.HTTP_400_BAD_REQUEST)
        data = serializer.validated_data

        konflikt = _pruefe_ueberlappung(
            data['REUID'].pk,
            data.get('ContractValidFrom'),
            data.get('ContractValidUntil'),
            ART_MIETER,
            data['MietVID'],
        )
        if konflikt is not None:
            return konflikt

        obj, _ = ReuMietV.objects.update_or_create(MietVID=data['MietVID'], defaults=data)
        return Response(ReuMietVSerializer(obj).data)


# ---------------------------------------------------------------------------
# ReuEigentuemer - Gegenstueck zu MietV fuer Eigentumsverhaeltnisse
# Quelle in xin: tblREUOwnerLinker
# ---------------------------------------------------------------------------

class EigentuemerByREIDView(APIView):
    """GET /api/eigentuemer/{reid} - alle Eigentumsverhaeltnisse einer Immobilie."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request, reid):
        qs = (
            ReuEigentuemer.objects
            .filter(REUID__REID=reid)
            .order_by('REUID', 'ValidFrom')
        )
        return Response(ReuEigentuemerSerializer(qs, many=True).data)


class EigentuemerStoreOrUpdateView(APIView):
    """PUT /api/eigentuemer - Eigentumsverhaeltnis anlegen oder aktualisieren."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def put(self, request):
        serializer = ReuEigentuemerSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(list(serializer.errors.values())[0], status=status.HTTP_400_BAD_REQUEST)
        data = serializer.validated_data

        konflikt = _pruefe_ueberlappung(
            data['REUID'].pk,
            data.get('ValidFrom'),
            data.get('ValidUntil'),
            ART_EIGENTUEMER,
            data['EigentumID'],
        )
        if konflikt is not None:
            return konflikt

        obj, _ = ReuEigentuemer.objects.update_or_create(
            EigentumID=data['EigentumID'], defaults=data
        )
        return Response(ReuEigentuemerSerializer(obj).data)


# ---------------------------------------------------------------------------
# RefVerRahmen – migrated from RefVerRahmenController
# ---------------------------------------------------------------------------

class RefVerRahmenStoreOrUpdateView(APIView):
    """PUT /api/refverbrrahmen – create or update reference consumption frame."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def put(self, request):
        serializer = VISysRefVerbrauchRahmenSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(list(serializer.errors.values())[0], status=status.HTTP_400_BAD_REQUEST)
        data = serializer.validated_data
        obj, _ = VISysRefVerbrauchRahmen.objects.update_or_create(
            VISysRefVerbrID=data['VISysRefVerbrID'], defaults=data
        )
        return Response(VISysRefVerbrauchRahmenSerializer(obj).data)


# ---------------------------------------------------------------------------
# RefVerDaten – migrated from RefVerDatenController
# ---------------------------------------------------------------------------

class RefVerDatenStoreOrUpdateView(APIView):
    """PUT /api/refverbrdaten – bulk create or update reference data points."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def put(self, request):
        data = request.data if isinstance(request.data, list) else [request.data]
        serializer = VISysRefVerbrauchsDSSerializer(data=data, many=True)
        if not serializer.is_valid():
            return Response(_first_error_message(serializer.errors), status=status.HTTP_400_BAD_REQUEST)
        count = 0
        for item in serializer.validated_data:
            VISysRefVerbrauchsDS.objects.update_or_create(
                RefVerBrDatID=item['RefVerBrDatID'], defaults=item
            )
            count += 1
        return Response(
            f'{count} Datensätze wurden neu eingetragen / aktualisiert (oder waren schon vorhanden)',
            status=status.HTTP_201_CREATED
        )


# ---------------------------------------------------------------------------
# VerRahmen – migrated from VerRahmenController
# ---------------------------------------------------------------------------

class VerRahmenStoreOrUpdateView(APIView):
    """PUT /api/verbrrahmen – bulk create or update consumption frames."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def put(self, request):
        data = request.data if isinstance(request.data, list) else [request.data]
        serializer = VISysVerbrauchRahmenSerializer(data=data, many=True)
        if not serializer.is_valid():
            return Response(_first_error_message(serializer.errors), status=status.HTTP_400_BAD_REQUEST)
        count = 0
        for item in serializer.validated_data:
            VISysVerbrauchRahmen.objects.update_or_create(
                VISysVerbrauchsID=item['VISysVerbrauchsID'], defaults=item
            )
            count += 1
        return Response(count, status=status.HTTP_201_CREATED)


# ---------------------------------------------------------------------------
# VerDaten – migrated from VerDatenController
# ---------------------------------------------------------------------------

class VerDatenView(APIView):
    """
    POST /api/verbrdaten – bulk create consumption data points.
    PUT  /api/verbrdaten – bulk create or update consumption data points.
    Migrated from VerDatenController.
    """
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def post(self, request):
        data = request.data if isinstance(request.data, list) else [request.data]
        serializer = VISysVerbrauchsDSSerializer(data=data, many=True)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        count = 0
        for item in serializer.validated_data:
            VISysVerbrauchsDS.objects.create(**item)
            count += 1
        return Response(count, status=status.HTTP_201_CREATED)

    def put(self, request):
        data = request.data if isinstance(request.data, list) else [request.data]
        serializer = VISysVerbrauchsDSSerializer(data=data, many=True)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        for item in serializer.validated_data:
            VISysVerbrauchsDS.objects.update_or_create(
                VerBrDatID=item['VerBrDatID'], defaults=item
            )
        return Response('Daten wurden neu eingetragen / aktualisiert', status=status.HTTP_201_CREATED)


# ---------------------------------------------------------------------------
# Me / Token – migrated from ApiUserController + inline token route
# ---------------------------------------------------------------------------

class MeView(APIView):
    """GET /api/me – return current API user info."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    # def get(self, request):
    #     return Response(ApiUserSerializer(request.user).data)


class TokenCreateView(APIView):
    """POST /api/me/tokencreate – create a new auth token for current user."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def post(self, request):
        from rest_framework.authtoken.models import Token
        # Delete existing token and create a new one
        Token.objects.filter(user=request.user).delete()
        token = Token.objects.create(user=request.user)
        return Response({'token': token.key})


# ---------------------------------------------------------------------------
# Anmelde-Log / Besuche – inkrementeller Abruf fuer die Statistik in xin.
# xin merkt sich die hoechste uebernommene id und fragt mit ?seit_id=N nach.
# ---------------------------------------------------------------------------

LOG_SEITENGROESSE = 5000


def _seit_id(request):
    try:
        return max(int(request.query_params.get('seit_id', 0)), 0)
    except (TypeError, ValueError):
        return 0


class AnmeldungenView(APIView):
    """GET /api/anmeldungen?seit_id=N – Anmeldungen mit id > N (max. 5000)."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request):
        qs = (
            NutzerAnmeldung.objects
            .filter(id__gt=_seit_id(request))
            .select_related('ip_info')
            .order_by('id')[:LOG_SEITENGROESSE]
        )
        daten = []
        for a in qs:
            ip_info = getattr(a, 'ip_info', None)
            daten.append({
                'id': a.id,
                'PersonenID': a.PersonenID,
                'zeitpunkt': a.zeitpunkt,
                'erfolgreich': a.erfolgreich,
                'ip': ip_info.ip if ip_info else None,
                'user_agent': ip_info.user_agent if ip_info else None,
            })
        return Response(daten)


class BesucheView(APIView):
    """GET /api/besuche?seit_id=N – Besuche (Nutzer/Tag) mit id > N (max. 5000)."""
    authentication_classes = [AdminTokenAuthentication]
    permission_classes = API_PERMISSIONS

    def get(self, request):
        qs = (
            NutzerBesuch.objects
            .filter(id__gt=_seit_id(request))
            .order_by('id')
            .values('id', 'PersonenID', 'tag', 'erster_zugriff')[:LOG_SEITENGROESSE]
        )
        return Response(list(qs))
