package kr.co.accura.wbx.spring.admin;

import kr.co.accura.wbx.spring.auth.*;
import kr.co.accura.wbx.spring.audit.AuditLogRepository;
import kr.co.accura.wbx.spring.config.WbxSpringProperties;
import kr.co.accura.wbx.spring.config.WbxSystemConfig;
import kr.co.accura.wbx.spring.rbac.*;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/admin")
@RequiredArgsConstructor
public class AdminViewController {

    private final WbxUserRepository userRepository;
    private final LoginHistoryRepository loginHistoryRepository;
    private final WbxRoleRepository roleRepository;
    private final RolePermissionRepository permissionRepository;
    private final PasswordEncoder passwordEncoder;
    private final WbxSpringProperties props;
    private final AuditLogRepository auditLogRepository;
    private final WbxSystemConfigRepository systemConfigRepository;
    private final WbxUserRoleRepository userRoleRepository;

    // ===== 대시보드 =====
    @GetMapping
    public String dashboard(Model model) {
        model.addAttribute("userCount", userRepository.countByIsActiveTrue());
        model.addAttribute("totalUsers", userRepository.count());
        model.addAttribute("loginCount", loginHistoryRepository.countByAction("LOGIN_SUCCESS"));
        model.addAttribute("roleCount", roleRepository.count());
        return "admin/dashboard";
    }

    // ===== 사용자 관리 =====
    @GetMapping("/users")
    public String userList(Model model) {
        model.addAttribute("users", userRepository.findAll());
        return "admin/users";
    }

    @PostMapping("/users/add")
    public String addUser(@RequestParam String email,
                           @RequestParam String username,
                           @RequestParam String password,
                           @RequestParam(required = false) String fullName,
                           @RequestParam(required = false) String phone,
                           @RequestParam(required = false) String positionTitle,
                           @RequestParam(required = false) String employeeNumber,
                           @RequestParam(required = false) Boolean isAdmin,
                           RedirectAttributes ra) {
        if (userRepository.existsByEmail(email)) {
            ra.addFlashAttribute("error", "이미 존재하는 이메일: " + email);
            return "redirect:/admin/users";
        }
        if (userRepository.existsByUsername(username)) {
            ra.addFlashAttribute("error", "이미 존재하는 사용자명: " + username);
            return "redirect:/admin/users";
        }
        WbxUser user = WbxUser.builder()
                .email(email)
                .username(username)
                .hashedPassword(passwordEncoder.encode(password))
                .fullName(fullName)
                .phone(phone)
                .positionTitle(positionTitle)
                .employeeNumber(employeeNumber != null && !employeeNumber.isBlank() ? employeeNumber : null)
                .isActive(true)
                .isAdmin(isAdmin != null && isAdmin)
                .build();
        userRepository.save(user);

        ra.addFlashAttribute("message", "사용자가 추가되었습니다: " + email);
        return "redirect:/admin/users/" + user.getId();
    }

    @GetMapping("/users/{id}")
    public String userDetail(@PathVariable Long id, Model model) {
        model.addAttribute("user", userRepository.findById(id).orElse(null));
        model.addAttribute("loginHistory",
                loginHistoryRepository.findByUserIdOrderByCreatedAtDesc(id, PageRequest.of(0, 10)));
        model.addAttribute("allRoles", roleRepository.findAll());
        model.addAttribute("userRoles", userRoleRepository.findByUserId(id));
        return "admin/user-detail";
    }

    @PostMapping("/users/{id}/update")
    public String updateUser(@PathVariable Long id,
                              @RequestParam String fullName,
                              @RequestParam(required = false) String phone,
                              @RequestParam(required = false) String positionTitle,
                              @RequestParam(required = false) String employeeNumber,
                              @RequestParam(required = false) Boolean isAdmin,
                              RedirectAttributes ra) {
        userRepository.findById(id).ifPresent(user -> {
            user.setFullName(fullName);
            user.setPhone(phone);
            user.setPositionTitle(positionTitle);
            user.setEmployeeNumber(employeeNumber != null && !employeeNumber.isBlank() ? employeeNumber : null);
            user.setAdmin(isAdmin != null && isAdmin);
            userRepository.save(user);
        });
        ra.addFlashAttribute("message", "사용자 정보가 수정되었습니다.");
        return "redirect:/admin/users/" + id;
    }

    @PostMapping("/users/{id}/delete")
    public String deleteUser(@PathVariable Long id, RedirectAttributes ra) {
        userRepository.findById(id).ifPresent(user -> {
            userRoleRepository.deleteByUserId(id);
            userRepository.delete(user);
            ra.addFlashAttribute("message", "사용자가 삭제되었습니다: " + user.getEmail());
        });
        return "redirect:/admin/users";
    }

    @PostMapping("/users/{id}/unlock")
    public String unlockUser(@PathVariable Long id, RedirectAttributes ra) {
        userRepository.findById(id).ifPresent(user -> {
            user.setFailedLoginAttempts(0);
            user.setLockedUntil(null);
            userRepository.save(user);
        });
        ra.addFlashAttribute("message", "계정 잠금이 해제되었습니다.");
        return "redirect:/admin/users/" + id;
    }

    @PostMapping("/users/{id}/reset-password")
    public String resetPassword(@PathVariable Long id, RedirectAttributes ra) {
        userRepository.findById(id).ifPresent(user -> {
            String temp = "Temp" + System.currentTimeMillis() % 10000 + "!";
            user.setHashedPassword(passwordEncoder.encode(temp));
            user.setMustChangePassword(true);
            userRepository.save(user);
            ra.addFlashAttribute("message", "임시 비밀번호: " + temp);
        });
        return "redirect:/admin/users/" + id;
    }

    @PostMapping("/users/{id}/toggle-status")
    public String toggleStatus(@PathVariable Long id, RedirectAttributes ra) {
        userRepository.findById(id).ifPresent(user -> {
            user.setActive(!user.isActive());
            userRepository.save(user);
            ra.addFlashAttribute("message", user.isActive() ? "계정 활성화" : "계정 비활성화");
        });
        return "redirect:/admin/users/" + id;
    }

    // ===== 사용자 역할 할당 =====
    @CacheEvict(value = {"permissions", "deptScopes"}, allEntries = true)
    @PostMapping("/users/{userId}/roles/add")
    public String addUserRole(@PathVariable Long userId,
                               @RequestParam Long roleId,
                               RedirectAttributes ra) {
        WbxUserRole ur = WbxUserRole.builder()
                .userId(userId)
                .roleId(roleId)
                .build();
        userRoleRepository.save(ur);
        ra.addFlashAttribute("message", "역할이 할당되었습니다.");
        return "redirect:/admin/users/" + userId;
    }

    @CacheEvict(value = {"permissions", "deptScopes"}, allEntries = true)
    @PostMapping("/users/{userId}/roles/{urId}/delete")
    public String removeUserRole(@PathVariable Long userId,
                                  @PathVariable Long urId,
                                  RedirectAttributes ra) {
        userRoleRepository.deleteById(urId);
        ra.addFlashAttribute("message", "역할이 해제되었습니다.");
        return "redirect:/admin/users/" + userId;
    }

    // ===== 역할 관리 =====
    @GetMapping("/roles")
    public String roleList(Model model) {
        model.addAttribute("roles", roleRepository.findAll());
        return "admin/roles";
    }

    @PostMapping("/roles/add")
    public String addRole(@RequestParam String code,
                           @RequestParam String name,
                           @RequestParam(required = false) String description,
                           RedirectAttributes ra) {
        if (roleRepository.findByCode(code).isPresent()) {
            ra.addFlashAttribute("error", "이미 존재하는 역할 코드: " + code);
            return "redirect:/admin/roles";
        }
        kr.co.accura.wbx.spring.rbac.WbxRole role = kr.co.accura.wbx.spring.rbac.WbxRole.builder()
                .code(code.toUpperCase())
                .name(name)
                .description(description)
                .isSystem(false)
                .build();
        roleRepository.save(role);
        ra.addFlashAttribute("message", "역할이 추가되었습니다: " + code);
        return "redirect:/admin/roles";
    }

    @GetMapping("/roles/{id}")
    public String roleDetail(@PathVariable Long id, Model model) {
        model.addAttribute("role", roleRepository.findById(id).orElse(null));
        model.addAttribute("permissions", permissionRepository.findByRoleId(id));
        model.addAttribute("deptScopes", kr.co.accura.wbx.spring.rbac.DeptScope.values());
        return "admin/role-detail";
    }

    @PostMapping("/roles/{id}/update")
    public String updateRole(@PathVariable Long id,
                              @RequestParam String name,
                              @RequestParam(required = false) String description,
                              RedirectAttributes ra) {
        roleRepository.findById(id).ifPresent(role -> {
            role.setName(name);
            role.setDescription(description);
            roleRepository.save(role);
        });
        ra.addFlashAttribute("message", "역할이 수정되었습니다.");
        return "redirect:/admin/roles/" + id;
    }

    @PostMapping("/roles/{id}/delete")
    public String deleteRole(@PathVariable Long id, RedirectAttributes ra) {
        roleRepository.findById(id).ifPresent(role -> {
            if (role.isSystem()) {
                ra.addFlashAttribute("error", "시스템 역할은 삭제할 수 없습니다.");
                return;
            }
            permissionRepository.deleteByRoleId(id);
            roleRepository.delete(role);
            ra.addFlashAttribute("message", "역할이 삭제되었습니다: " + role.getCode());
        });
        return "redirect:/admin/roles";
    }

    // ===== 권한 추가/삭제 =====
    @CacheEvict(value = {"permissions", "deptScopes"}, allEntries = true)
    @PostMapping("/roles/{roleId}/permissions/add")
    public String addPermission(@PathVariable Long roleId,
                                 @RequestParam String module,
                                 @RequestParam String action,
                                 @RequestParam String deptScope,
                                 RedirectAttributes ra) {
        RolePermission perm = RolePermission.builder()
                .roleId(roleId)
                .module(module.toUpperCase())
                .action(action.toUpperCase())
                .deptScope(kr.co.accura.wbx.spring.rbac.DeptScope.valueOf(deptScope))
                .build();
        permissionRepository.save(perm);
        ra.addFlashAttribute("message", "권한이 추가되었습니다: " + module + "." + action);
        return "redirect:/admin/roles/" + roleId;
    }

    @CacheEvict(value = {"permissions", "deptScopes"}, allEntries = true)
    @PostMapping("/permissions/{id}/delete")
    public String deletePermission(@PathVariable Long id, RedirectAttributes ra) {
        RolePermission perm = permissionRepository.findById(id).orElse(null);
        if (perm != null) {
            Long roleId = perm.getRoleId();
            permissionRepository.delete(perm);
            ra.addFlashAttribute("message", "권한이 삭제되었습니다.");
            return "redirect:/admin/roles/" + roleId;
        }
        return "redirect:/admin/permissions";
    }

    // ===== 로그인 이력 =====
    @GetMapping("/login-history")
    public String loginHistory(Model model) {
        model.addAttribute("logs",
                loginHistoryRepository.findAllByOrderByCreatedAtDesc(PageRequest.of(0, 50)));
        return "admin/login-history";
    }

    // ===== 감사 로그 =====
    @GetMapping("/audit-logs")
    public String auditLogs(Model model) {
        model.addAttribute("logs",
                auditLogRepository.findAll(PageRequest.of(0, 100, Sort.by(Sort.Direction.DESC, "createdAt"))));
        return "admin/audit-logs";
    }

    // ===== 시스템 설정 =====
    @GetMapping("/config")
    public String systemConfig(Model model) {
        model.addAttribute("configs", systemConfigRepository.findAll());
        return "admin/config";
    }

    @PostMapping("/config/save")
    public String saveConfig(@RequestParam String configKey,
                              @RequestParam String configValue,
                              @RequestParam(required = false) String description,
                              RedirectAttributes ra) {
        WbxSystemConfig config = systemConfigRepository.findByConfigKey(configKey)
                .orElse(new WbxSystemConfig());
        config.setConfigKey(configKey);
        config.setConfigValue(configValue);
        config.setDescription(description);
        systemConfigRepository.save(config);
        ra.addFlashAttribute("message", "설정이 저장되었습니다: " + configKey);
        return "redirect:/admin/config";
    }

    // ===== 권한 매트릭스 =====
    @GetMapping("/permissions")
    public String permissions(Model model) {
        model.addAttribute("roles", roleRepository.findAll());
        model.addAttribute("permissions", permissionRepository.findAll());
        return "admin/permissions";
    }

    // ===== 시스템 상태 =====
    @GetMapping("/system-health")
    public String systemHealth(Model model) {
        MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
        long heapUsed = mem.getHeapMemoryUsage().getUsed() / (1024 * 1024);
        long heapMax = mem.getHeapMemoryUsage().getMax() / (1024 * 1024);

        Map<String, Object> health = new LinkedHashMap<>();
        health.put("JVM Heap", heapUsed + " MB / " + heapMax + " MB");
        health.put("Active Threads", Thread.activeCount());
        health.put("OS", System.getProperty("os.name") + " " + System.getProperty("os.arch"));
        health.put("Java", System.getProperty("java.version"));
        health.put("Spring Boot", org.springframework.boot.SpringBootVersion.getVersion());
        health.put("Total Users", userRepository.count());
        health.put("Active Users", userRepository.countByIsActiveTrue());

        model.addAttribute("health", health);
        return "admin/system-health";
    }
}
