"""Back-office views (member-facing, gated by main_character_required + basic_access)."""

from django.contrib.auth.decorators import login_required, permission_required
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from ..forms import (
    AddHullForm, AddStockroomForm, EditHullForm, EditStockroomForm, ShopForm,
)
from ..market import jita_prices
from ..models import (
    AUTO_STOCK, FIXED_PRICE, HULL, PCT_MODES, HullListing, Shop, ShopSource,
)
from ..permissions import can_manage, corp_shops_for, personal_shops_for
from ..sources import container_name_for
from ..stock import recompute_shop_stock, ship_type_ids_in_source
from ..tasks import TASK_PRIORITY, refresh_price_for_type


@login_required
@permission_required("shop.basic_access")
def index(request):
    return render(request, "shop/index.html", {
        "personal_shops": personal_shops_for(request.user),
        "corp_shops": corp_shops_for(request.user),
        "can_manage_corp": (
            request.user.has_perm("shop.manage_corporation_shops")
            or request.user.is_superuser
        ),
    })


@login_required
@permission_required("shop.basic_access")
def create(request):
    if request.method == "POST":
        form = ShopForm(request.POST, user=request.user)
        if form.is_valid():
            form.save()
            return redirect("backoffice:index")
    else:
        form = ShopForm(user=request.user)
    return render(request, "shop/shop_form.html", {"form": form, "is_edit": False})


@login_required
@permission_required("shop.basic_access")
def edit(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        form = ShopForm(request.POST, instance=shop, user=request.user)
        if form.is_valid():
            form.save()
            return redirect("backoffice:index")
    else:
        form = ShopForm(instance=shop, user=request.user)
    return render(request, "shop/shop_form.html", {"form": form, "is_edit": True, "shop": shop})


@login_required
@permission_required("shop.basic_access")
def delete(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        shop.delete()
        return redirect("backoffice:index")
    return render(request, "shop/shop_confirm_delete.html", {"shop": shop})


@login_required
@permission_required("shop.basic_access")
def manage(request, pk):
    import json

    from ..sources import source_tree

    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    return render(request, "shop/manage.html", {
        "shop": shop,
        "listings": HullListing.objects.filter(shop=shop)
        .select_related("eve_type", "eve_type__eve_group").order_by("eve_type__name"),
        "hull_sources": shop.sources.filter(section=HULL)
        .select_related("character__eve_character", "location"),
        "add_hull_form": AddHullForm(),
        "add_stockroom_form": AddStockroomForm(owner=request.user),
        "source_tree_json": json.dumps(source_tree(request.user)),
    })


@login_required
@permission_required("shop.basic_access")
def add_stockroom(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        form = AddStockroomForm(request.POST, owner=request.user)
        if form.is_valid():
            container_item_id = form.cleaned_data.get("container_item_id") or None
            source = ShopSource.objects.create(
                shop=shop, section=HULL,
                character_id=form.cleaned_data["character_id"],
                location_id=form.cleaned_data["location_id"],
                container_item_id=container_item_id,
                container_name=container_name_for(
                    form.cleaned_data["character_id"], container_item_id
                ),
                price_mode=form.cleaned_data["price_mode"],
                price_pct=form.cleaned_data.get("price_pct"),
            )
            # Auto-list hulls found in the stockroom. First-seen hulls inherit the
            # source's price rule (get_or_create defaults apply on create only).
            type_ids = ship_type_ids_in_source(source)
            for type_id in type_ids:
                HullListing.objects.get_or_create(
                    shop=shop, eve_type_id=type_id,
                    defaults={
                        "price_mode": source.price_mode,
                        "price_pct": source.price_pct,
                    },
                )
            recompute_shop_stock(shop)
            # Refresh prices for every %-mode hull this stockroom stocks (new or
            # pre-existing) so adding a stockroom reflects current Jita prices.
            pct_type_ids = (
                shop.hull_listings.filter(
                    eve_type_id__in=type_ids, price_mode__in=PCT_MODES
                )
                .values_list("eve_type_id", flat=True)
                .distinct()
            )
            for type_id in pct_type_ids:
                refresh_price_for_type.apply_async(args=[type_id], priority=TASK_PRIORITY)
    return redirect("backoffice:manage", pk=shop.pk)


@login_required
@permission_required("shop.basic_access")
def edit_stockroom(request, pk, source_id):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    source = get_object_or_404(ShopSource, pk=source_id, shop=shop, section=HULL)
    if request.method == "POST":
        form = EditStockroomForm(request.POST)
        if form.is_valid():
            source.price_mode = form.cleaned_data["price_mode"]
            source.price_pct = form.cleaned_data.get("price_pct")
            source.save(update_fields=["price_mode", "price_pct"])
    return redirect("backoffice:manage", pk=shop.pk)


@login_required
@permission_required("shop.basic_access")
def remove_stockroom(request, pk, source_id):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        ShopSource.objects.filter(pk=source_id, shop=shop, section=HULL).delete()
        recompute_shop_stock(shop)
    return redirect("backoffice:manage", pk=shop.pk)


def _apply_modes(listing, cd):
    """Apply stock/price mode fields from a validated form to a listing + save.

    Auto stock recomputes from sources; a pct price mode fetches a live Jita price
    synchronously (single listing) and keeps-last-known if ESI is unavailable.
    """
    listing.stock_mode = cd["stock_mode"]
    listing.price_mode = cd["price_mode"]
    listing.price_pct = cd.get("price_pct")
    listing.persist = cd["persist"]
    listing.description = cd.get("description", "")
    if cd["price_mode"] == FIXED_PRICE:
        listing.price = cd.get("price") or 0
    if cd["stock_mode"] != AUTO_STOCK:
        listing.stock = cd.get("stock") or 0
    listing.save()
    if listing.stock_mode == AUTO_STOCK:
        listing.recompute_stock()
    if listing.price_mode in PCT_MODES:
        try:
            p = jita_prices(listing.eve_type_id)
            if listing.apply_jita_price(p["buy"], p["sell"]):
                listing.save(update_fields=["price"])
        except Exception:  # noqa: BLE001 - keep last known; cron backfills
            pass


@login_required
@permission_required("shop.basic_access")
def add_hull(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        form = AddHullForm(request.POST)
        if form.is_valid():
            listing, _ = HullListing.objects.get_or_create(
                shop=shop, eve_type=form.cleaned_data["eve_type"]
            )
            _apply_modes(listing, form.cleaned_data)
    return redirect("backoffice:manage", pk=shop.pk)


@login_required
@permission_required("shop.basic_access")
def edit_hull(request, pk, listing_id):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    listing = get_object_or_404(HullListing, pk=listing_id, shop=shop)
    if request.method == "POST":
        form = EditHullForm(request.POST)
        if form.is_valid():
            _apply_modes(listing, form.cleaned_data)
    return redirect("backoffice:manage", pk=shop.pk)


@login_required
@permission_required("shop.basic_access")
def remove_hull(request, pk, listing_id):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        HullListing.objects.filter(pk=listing_id, shop=shop).delete()
    return redirect("backoffice:manage", pk=shop.pk)


@login_required
@permission_required("shop.basic_access")
def toggle_featured(request, pk, listing_id):
    shop = get_object_or_404(Shop, pk=pk)
    if not can_manage(request.user, shop):
        return HttpResponseForbidden()
    if request.method == "POST":
        listing = get_object_or_404(HullListing, pk=listing_id, shop=shop)
        listing.featured = not listing.featured
        listing.featured_at = timezone.now() if listing.featured else None
        listing.save(update_fields=["featured", "featured_at"])
    return redirect("backoffice:manage", pk=shop.pk)
