package com.petshop.backend.config;

import com.petshop.backend.entity.User;
import com.petshop.backend.security.AppPrincipal;
import com.petshop.backend.service.ActivityLogService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
@Order(Ordered.LOWEST_PRECEDENCE - 20)
public class ActivityLoggingFilter extends OncePerRequestFilter {

    private final ActivityLogService activityLogService;

    public ActivityLoggingFilter(ActivityLogService activityLogService) {
        this.activityLogService = activityLogService;
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String uri = request.getRequestURI();
        if (uri == null || uri.isBlank()) return true;
        if (!uri.startsWith("/api/")) return true;
        String lower = uri.toLowerCase(java.util.Locale.ROOT);
        return lower.startsWith("/api/v1/health")
                || lower.startsWith("/api/v1/activity-logs")
                || lower.startsWith("/v3/api-docs")
                || lower.startsWith("/swagger-ui")
                || lower.startsWith("/ws/");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        filterChain.doFilter(request, response);
        recordActivity(request, response);
    }

    private void recordActivity(HttpServletRequest request, HttpServletResponse response) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) return;

        Long userId = null;
        User.Role role = null;
        Object principal = authentication.getPrincipal();
        if (principal instanceof AppPrincipal appPrincipal) {
            userId = appPrincipal.getUserId();
            role = appPrincipal.getRole();
        } else if (authentication instanceof UsernamePasswordAuthenticationToken token
                && token.getPrincipal() instanceof AppPrincipal appPrincipal) {
            userId = appPrincipal.getUserId();
            role = appPrincipal.getRole();
        }

        if (userId == null || role == null) return;
        if ("GET".equalsIgnoreCase(request.getMethod())) return;

        String method = request.getMethod();
        String uri = request.getRequestURI();
        int status = response.getStatus();

        String technical = method + " " + uri + " → " + status;
        String description = describe(method, uri, status);
        String activity = description != null ? description + "  |  " + technical : technical;

        activityLogService.record(userId, activity);
    }

    private String describe(String method, String rawUri, int status) {
        String uri = rawUri.contains("?") ? rawUri.substring(0, rawUri.indexOf('?')) : rawUri;
        String[] parts = uri.replaceFirst("^/+", "").split("/");
        if (parts.length < 3) return null;

        String r = parts[2];
        String seg3 = parts.length > 3 ? parts[3] : null;
        String seg4 = parts.length > 4 ? parts[4] : null;
        String seg5 = parts.length > 5 ? parts[5] : null;

        boolean seg3IsId = seg3 != null && seg3.matches("\\d+");
        boolean seg4IsId = seg4 != null && seg4.matches("\\d+");
        String id = seg3IsId ? seg3 : null;
        String sub = seg3IsId ? seg4 : seg3;
        String subsub = seg3IsId ? seg5 : seg4;

        boolean isGet    = "GET".equalsIgnoreCase(method);
        boolean isPost   = "POST".equalsIgnoreCase(method);
        boolean isPut    = "PUT".equalsIgnoreCase(method);
        boolean isPatch  = "PATCH".equalsIgnoreCase(method);
        boolean isDelete = "DELETE".equalsIgnoreCase(method);
        boolean failed   = status >= 400;

        switch (r) {
            case "auth" -> {
                if ("login".equals(seg3) && isPost)           return failed ? "Failed login attempt" : "Logged in";
                if ("logout".equals(seg3) && isPost)          return "Logged out";
                if ("register".equals(seg3) && isPost)        return failed ? "Failed registration attempt" : "Registered a new account";
                if ("forgot-password".equals(seg3) && isPost) return "Requested a password reset";
                if ("reset-password".equals(seg3) && isPost)  return "Reset their password";
                if ("me".equals(seg3) && isPut)               return "Updated their profile";
                if ("me".equals(seg3) && "avatar".equals(sub) && isPost)   return "Uploaded a profile picture";
                if ("me".equals(seg3) && "avatar".equals(sub) && isDelete) return "Removed their profile picture";
            }
            case "cart" -> {
                if ("add".equals(seg3) && isPost)             return "Added an item to cart";
                if ("update".equals(seg3) && isPut)           return "Updated a cart item";
                if ("remove".equals(seg3) && isDelete)        return "Removed an item from cart";
                if ("clear".equals(seg3) && isDelete)         return "Cleared their cart";
                if ("apply-coupon".equals(seg3) && isPost)    return "Applied a coupon to cart";
                if ("checkout".equals(seg3)) {
                    if ("complete".equals(seg4) && isPost)    return "Completed a purchase";
                    if ("cancel".equals(seg4) && isPost)      return "Cancelled checkout";
                    if (isPost)                               return "Started checkout";
                }
            }
            case "chat" -> {
                if ("conversations".equals(seg3) && isPost && seg4 == null) return "Started a new chat conversation";
                if ("conversations".equals(seg3) && seg4IsId) {
                    String convId = seg4;
                    String chatSub = parts.length > 5 ? parts[5] : null;
                    if ("messages".equals(seg5) && isPost)      return "Sent a chat message";
                    if ("attachments".equals(seg5) && isPost)   return "Sent a file in chat";
                    if ("request-human".equals(seg5) && isPost) return "Requested human support in chat";
                    if (chatSub == null && isPut)               return "Updated chat conversation #" + convId;
                }
            }
            case "ai-chat" -> {
                if ("message".equals(seg3) && isPost) return "Sent a message to the AI assistant";
            }
            case "product-suppliers" -> {
                if (isPost && seg3 == null)           return "Linked a product to a supplier";
                if (seg3IsId && seg4IsId && isPut)    return "Updated product-supplier link";
                if (seg3IsId && seg4IsId && isDelete) return "Removed product-supplier link";
                if (isDelete && !seg3IsId)            return "Removed multiple product-supplier links";
            }
        }

        String label = resourceLabel(r);
        if (label == null) return null;

        if ("image".equals(sub) && id != null) {
            if (isPost)   return "Uploaded image for " + label + " #" + id;
            if (isDelete) return "Removed image from " + label + " #" + id;
        }

        if ("cancel".equals(sub) && id != null && isPatch) return "Cancelled " + label + " #" + id;

        if (isPost && id == null) {
            if ("request".equals(seg3)) return "Submitted an adoption request";
            if ("bulk-delete".equals(seg3)) return "Deleted multiple " + plural(label);
            return "Created a new " + label;
        }
        if ((isPut || isPatch) && id != null && sub == null) return "Updated " + label + " #" + id;
        if (isDelete && id != null && sub == null)           return "Deleted " + label + " #" + id;
        if (isDelete && id == null)                          return "Deleted multiple " + plural(label);

        return null;
    }

    private String resourceLabel(String resource) {
        return switch (resource) {
            case "products"        -> "product";
            case "categories"      -> "category";
            case "customers"       -> "customer";
            case "employees"       -> "employee";
            case "users"           -> "user";
            case "pets"            -> "pet";
            case "my-pets"         -> "pet";
            case "appointments"    -> "appointment";
            case "adoptions"       -> "adoption";
            case "sales"           -> "sale";
            case "refunds"         -> "refund";
            case "inventory"       -> "inventory record";
            case "services"        -> "service";
            case "suppliers"       -> "supplier";
            case "purchase-orders" -> "purchase order";
            case "coupons"         -> "coupon";
            case "stores"          -> "store";
            default -> null;
        };
    }

    private String plural(String label) {
        if (label.endsWith("y")) return label.substring(0, label.length() - 1) + "ies";
        if (label.endsWith("s")) return label + "es";
        return label + "s";
    }
}
