from django.db.models import Q
from decimal import Decimal, InvalidOperation
import json
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from Settings.models import ApiCredential
from .models import Good
from .serializers import GoodSerializer


def add_cors_headers(response):
    response["Access-Control-Allow-Origin"] = "http://localhost:3000"
    response["Access-Control-Allow-Methods"] = "GET, POST, PATCH, DELETE, OPTIONS"
    response["Access-Control-Allow-Headers"] = "Content-Type"
    return response


def as_decimal(value, default="0"):
    try:
        return Decimal(str(value if value is not None else default))
    except (InvalidOperation, TypeError, ValueError):
        return Decimal(default)


def as_int(value, default=0):
    try:
        return int(value if value is not None else default)
    except (TypeError, ValueError):
        return default


def select_hesabfa_credential():
    active_credentials = ApiCredential.objects.filter(is_active=True)
    hesabfa_credential = active_credentials.filter(account_name_en__icontains="hesabfa").first()
    return hesabfa_credential or active_credentials.first()


def build_good_from_hesabfa_item(item):
    return Good(
        code=str(item.get("Code") or "").strip(),
        name=item.get("Name") or "",
        barcode=item.get("Barcode") or "",
        item_type=str(item.get("ItemType") if item.get("ItemType") is not None else ""),
        unit=item.get("Unit") or "",
        sub_unit=item.get("SubUnit") or "",
        conversion_factor=as_decimal(item.get("ConversionFactor"), "1"),
        stock=as_decimal(item.get("Stock")),
        buy_price=as_decimal(item.get("BuyPrice")),
        sell_price=as_decimal(item.get("SellPrice")),
        purchases_title=item.get("PurchasesTitle") or "",
        sales_title=item.get("SalesTitle") or "",
        node_family=item.get("NodeFamily") or "",
        tag=item.get("Tag") or "",
        description=item.get("Description") or "",
        product_code=item.get("ProductCode") or "",
        active=bool(item.get("Active", True)),
        tax_id=item.get("TaxId") or "",
        tax_unit=item.get("TaxUnit") or "",
        reorder_point=as_decimal(item.get("ReorderPoint")),
        lead_time=as_int(item.get("LeadTime")),
        minimum_order=as_decimal(item.get("MinimumOrder")),
        price_list=item.get("PriceList") or [],
    )


def request_hesabfa_items(credential, take, skip):
    payload = {
        "apiKey": credential.api_code,
        "userId": credential.user_id,
        "password": credential.password,
        "loginToken": credential.login_token,
        "queryInfo": {
            "sortBy": "Code",
            "sortDesc": False,
            "take": take,
            "skip": skip,
            "filters": [],
        },
    }
    request = Request(
        "https://api.hesabfa.com/v1/item/getItems",
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )

    with urlopen(request, timeout=45) as response:
        return json.loads(response.read().decode("utf-8"))


class GoodListView(APIView):
    def options(self, request, *args, **kwargs):
        return add_cors_headers(Response(status=204))

    def get(self, request):
        page = max(1, int(request.query_params.get("page", 1)))
        page_size = max(1, int(request.query_params.get("page_size", 10)))
        search = request.query_params.get("search", "").strip()

        goods = Good.objects.all()
        total_count = goods.count()

        if search:
            goods = goods.filter(Q(name__icontains=search) | Q(code__icontains=search))

        filtered_count = goods.count()
        start = (page - 1) * page_size
        end = start + page_size
        serializer = GoodSerializer(goods[start:end], many=True)

        return add_cors_headers(
            Response(
                {
                    "results": serializer.data,
                    "total_count": total_count,
                    "filtered_count": filtered_count,
                }
            )
        )


class GoodSyncHesabfaView(APIView):
    def options(self, request, *args, **kwargs):
        return add_cors_headers(Response(status=status.HTTP_204_NO_CONTENT))

    def post(self, request):
        credential = select_hesabfa_credential()
        if not credential:
            return add_cors_headers(
                Response(
                    {"detail": "هیچ API فعال برای اتصال به حسابفا ثبت نشده است."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            )

        take = 100
        skip = 0
        fetched_count = 0
        created_count = 0
        skipped_count = 0

        try:
            while True:
                decoded = request_hesabfa_items(credential, take=take, skip=skip)

                if not decoded.get("Success"):
                    return add_cors_headers(
                        Response(
                            {
                                "detail": decoded.get("ErrorMessage") or "پاسخ حسابفا نامعتبر بود.",
                                "error_code": decoded.get("ErrorCode"),
                            },
                            status=status.HTTP_502_BAD_GATEWAY,
                        )
                    )

                result = decoded.get("Result") or {}
                items = result.get("List") or []
                if not items:
                    break

                fetched_count += len(items)
                existing_codes = set(
                    Good.objects.filter(
                        code__in=[str(item.get("Code") or "").strip() for item in items]
                    ).values_list("code", flat=True)
                )
                goods_to_create = []

                for item in items:
                    code = str(item.get("Code") or "").strip()
                    if not code:
                        skipped_count += 1
                        continue

                    if code in existing_codes:
                        skipped_count += 1
                        continue

                    goods_to_create.append(build_good_from_hesabfa_item(item))
                    existing_codes.add(code)

                if goods_to_create:
                    Good.objects.bulk_create(goods_to_create)
                    created_count += len(goods_to_create)

                skip += take
                total_count = int(result.get("FilteredCount") or result.get("TotalCount") or 0)
                if total_count and skip >= total_count:
                    break

        except (HTTPError, URLError, TimeoutError, json.JSONDecodeError) as exc:
            return add_cors_headers(
                Response(
                    {"detail": "ارتباط با حسابفا برقرار نشد.", "error": str(exc)},
                    status=status.HTTP_502_BAD_GATEWAY,
                )
            )

        return add_cors_headers(
            Response(
                {
                    "fetched_count": fetched_count,
                    "created_count": created_count,
                    "skipped_count": skipped_count,
                    "total_count": Good.objects.count(),
                }
            )
        )


class GoodDetailView(APIView):
    def options(self, request, *args, **kwargs):
        return add_cors_headers(Response(status=status.HTTP_204_NO_CONTENT))

    def patch(self, request, pk):
        try:
            good = Good.objects.get(pk=pk)
        except Good.DoesNotExist:
            return add_cors_headers(Response(status=status.HTTP_404_NOT_FOUND))

        serializer = GoodSerializer(good, data=request.data, partial=True)
        if not serializer.is_valid():
            return add_cors_headers(Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST))

        serializer.save()
        return add_cors_headers(Response(serializer.data))

    def delete(self, request, pk):
        try:
            good = Good.objects.get(pk=pk)
        except Good.DoesNotExist:
            return add_cors_headers(Response(status=status.HTTP_404_NOT_FOUND))

        good.delete()
        return add_cors_headers(Response(status=status.HTTP_204_NO_CONTENT))
