package com.MedInsuranceV2.Version20.Controller;

import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.MedInsuranceV2.Version20.BoughtInsurance.BoughtInsurance;
import com.MedInsuranceV2.Version20.BoughtInsurance.BoughtInsuranceService;
import com.MedInsuranceV2.Version20.Claim.Claim;
import com.MedInsuranceV2.Version20.Claim.ClaimService;
import com.MedInsuranceV2.Version20.Claim.PdfGeneratorService;
import com.MedInsuranceV2.Version20.Email.EmailService;
import com.MedInsuranceV2.Version20.Insurance.Insurance;
import com.MedInsuranceV2.Version20.Insurance.InsuranceService;
import com.MedInsuranceV2.Version20.PDF.PdfReportService;
import com.MedInsuranceV2.Version20.User.User;
import com.MedInsuranceV2.Version20.User.UserService;
import com.itextpdf.io.source.OutputStream;
import com.itextpdf.kernel.pdf.PdfOutputStream;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.api.Spaceable;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.Element;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap; // LinkedHashMap இறக்குமதி செய்யப்பட்டது
import java.util.List;
import java.util.Map; // Map இறக்குமதி செய்யப்பட்டது
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;

@Slf4j
@Controller
@RequestMapping("/admin") // இந்த கன்ட்ரோலருக்கான அனைத்து URL-களும் '/admin' உடன் தொடங்கும்
public class AdminController {

    @Autowired
    private UserService userService;

    @Autowired
    private InsuranceService insuranceService;

    @Autowired
    private ClaimService claimService;
    
    @Autowired
    private BoughtInsuranceService boughtInsuranceService;

    @Autowired
    private PdfGeneratorService pdfGeneratorService;
    
    @Autowired
    private EmailService emailService; 
    
    @Autowired
    private PdfReportService pdfReportService;
    
    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;
    
    private ScheduledFuture<?> dailyReportTask;// EmailService ஐ இறக்குமதி செய்யவும்
    // அட்மின் டாஷ்போர்டு
    @GetMapping("/dashboard")
    public String adminDashboard(HttpSession session, Model model) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null) {
            Optional<User> user = userService.findUserById(userId);
            if (user.isPresent() && "ADMIN".equals(user.get().getRole())) {
                model.addAttribute("loggedInAdmin", user.get());
                // Pass a flag to the JSP indicating if the scheduler is running
                model.addAttribute("isSchedulerRunning", dailyReportTask != null && !dailyReportTask.isDone());
                return "Admindashboard";
            }
        }
        return "redirect:/login";
    }
    @PostMapping("/scheduleDailyReport")
    @ResponseBody // This tells Spring to return JSON, not a view name
    public ResponseEntity<Map<String, Object>> scheduleDailyReport(HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        User loggedInUser = (User) session.getAttribute("loggedInUser");

        // Basic security check
        if (loggedInUser == null || !"ADMIN".equals(loggedInUser.getRole())) {
            response.put("success", false);
            response.put("message", "Unauthorized access.");
            return ResponseEntity.status(403).body(response);
        }

        // Check if a task is already scheduled
        if (dailyReportTask != null && !dailyReportTask.isDone()) {
            response.put("success", false);
            response.put("message", "Daily report scheduler is already running.");
            return ResponseEntity.ok(response);
        }

        try {
            // Define the task to be scheduled
            Runnable task = () -> {
                log.info("Attempting to generate and send daily report at {}", LocalDateTime.now());
                try {
                    // Generate PDF report (calling the new service)
                    byte[] pdfBytes = pdfReportService.generateAllBoughtInsurancesPdf(null); // Pass null for all plans
                    ByteArrayInputStream bais = new ByteArrayInputStream(pdfBytes);

                    // Get admin email for sending (replace with actual admin email or list of emails)
                    String adminEmail = "your.admin.email@example.com"; // Configure this securely
                    if (loggedInUser != null) { // Or get it from a configuration/DB
                        adminEmail = loggedInUser.getEmailId(); // Use the logged-in admin's email if available
                    }
                    
                    String subject = "Daily All Bought Insurances Report - " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    String body = "Dear Admin,\n\nPlease find attached your daily report on all bought insurance policies.\n\nRegards,\nYour System";
                    String filename = "All_Bought_Insurances_Report_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".pdf";

                    emailService.sendEmailWithAttachment1(adminEmail, subject, body, bais, filename, "application/pdf");
                    log.info("Daily report successfully generated and sent to {}", adminEmail);

                } catch (Exception e) {
                    log.error("Error generating or sending daily report: {}", e.getMessage(), e);
                    // In a real application, you might want to send an error notification
                }
            };

            // Schedule the task to run every 10 minutes
            // Cron expression for every 10 minutes: "0 */10 * * * ?"
            // For example, at 00:00, 00:10, 00:20, etc.
            dailyReportTask = taskScheduler.schedule(task, new CronTrigger("0 */10 * * * ?"));
            
            response.put("success", true);
            response.put("message", "Daily report scheduler started successfully! Reports will be sent every 10 minutes.");
            log.info("Daily report scheduler initiated by admin: {}", loggedInUser != null ? loggedInUser.getName() : "Unknown");

        } catch (Exception e) {
            log.error("Failed to schedule daily report: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "Failed to start daily report scheduler: " + e.getMessage());
        }
        return ResponseEntity.ok(response);
    }
    @PostMapping("/stopDailyReport")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> stopDailyReport(HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        User loggedInUser = (User) session.getAttribute("loggedInUser");

        // Basic security check
        if (loggedInUser == null || !"ADMIN".equals(loggedInUser.getRole())) {
            response.put("success", false);
            response.put("message", "Unauthorized access.");
            return ResponseEntity.status(403).body(response);
        }

        if (dailyReportTask != null) {
            boolean cancelled = dailyReportTask.cancel(true); // Attempt to cancel the task
            if (cancelled) {
                dailyReportTask = null; // Clear the reference
                response.put("success", true);
                response.put("message", "Daily report scheduler stopped successfully.");
                log.info("Daily report scheduler stopped by admin: {}", loggedInUser != null ? loggedInUser.getName() : "Unknown");
            } else {
                response.put("success", false);
                response.put("message", "Failed to stop daily report scheduler. It might have already completed or is running.");
                log.warn("Attempted to stop scheduler but it could not be cancelled. IsDone: {}", dailyReportTask.isDone());
            }
        } else {
            response.put("success", false);
            response.put("message", "Daily report scheduler is not currently running.");
            log.info("Attempted to stop scheduler, but no task was found running.");
        }
        return ResponseEntity.ok(response);
    }
    // Insurance Management
    @GetMapping("/insurance/viewAll")
    public String viewAllInsurance(Model model, HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        log.info("Manickam");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            List<Insurance> allInsurances = insuranceService.getAllInsurancePolicies();
            model.addAttribute("allInsurances", allInsurances);
            log.info("Manickam");
            return "admin/viewAllInsurance"; // src/main/resources/templates/admin/viewAllInsurance.jsp
        }
        return "redirect:/login";
    }

    @GetMapping("/insurance/add")
    public String addInsurancePage(Model model, HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            model.addAttribute("insurance", new Insurance()); // ஒரு புதிய இன்சூரன்ஸ் ஆப்ஜெக்ட் சேர்க்க
            return "admin/addInsurance"; // src/main/resources/templates/admin/addInsurance.jsp
        }
        return "redirect:/login";
    }

    @PostMapping("/insurance/add")
    public String addInsurance(@ModelAttribute Insurance insurance, HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            insuranceService.addInsurance(insurance);
            return "redirect:/admin/insurance/viewAll"; // சேர்த்த பிறகு அனைத்தையும் பார்க்க திருப்பிவிடவும்
        }
        return "redirect:/login";
    }
   
    @GetMapping("/insurance/edit")
    public String showEditInsuranceForm(@RequestParam("id") Long id, Model model,
                                        RedirectAttributes redirectAttributes) {
        Optional<Insurance> insuranceOptional = insuranceService.getInsuranceById(id);

        if (insuranceOptional.isPresent()) {
            model.addAttribute("insurance", insuranceOptional.get());
            // This will resolve to /WEB-INF/views/editInsurance.jsp
            return "admin/editInsurance";
        } else {
            // If the policy is not found, redirect back to the list with an error message
            redirectAttributes.addFlashAttribute("errorMessage", "Insurance policy with ID " + id + " not found for editing.");
            return "redirect:/admin/insurances";
        }
    }
    
    @PostMapping("/insurance/update")
    public String updateInsurance(@ModelAttribute Insurance insurance, // Binds form data to an Insurance object
                                  RedirectAttributes redirectAttributes) {
        try {
            // Use the updateInsurance method from your service
            Insurance updatedPolicy = insuranceService.updateInsurance(insurance);
            redirectAttributes.addFlashAttribute("successMessage", "Insurance policy updated successfully!");
        } catch (RuntimeException e) { // Catch the RuntimeException thrown by your service if ID not found
            redirectAttributes.addFlashAttribute("errorMessage", "Failed to update policy: " + e.getMessage());
            // If update fails, redirect back to the edit page with the error
            return "redirect:/admin/insurance/edit?id=" + insurance.getId();
        } catch (Exception e) { // Catch any other unexpected errors
            redirectAttributes.addFlashAttribute("errorMessage", "An unexpected error occurred during update: " + e.getMessage());
            return "redirect:/admin/insurance/edit?id=" + insurance.getId();
        }
        // Redirect back to the list of all insurances after a successful update
        return "redirect:/admin/insurance/viewAll";
    }

    @GetMapping("/insurance/delete")
    public String deleteInsurance(@RequestParam("id") Long id, RedirectAttributes redirectAttributes) {
        try {
            insuranceService.deleteInsurance(id);
            redirectAttributes.addFlashAttribute("successMessage", "Insurance policy deleted successfully!");
        } catch (Exception e) {
            redirectAttributes.addFlashAttribute("errorMessage", "Error deleting insurance policy with ID " + id + ": " + e.getMessage());
        }
        // Always redirect back to the list of all insurances after deletion attempt
        return "redirect:/admin/insurance/viewAll";
    }
    @GetMapping("/insurance/export/pdf")
    public void exportInsurancesToPdf(HttpServletResponse response) throws IOException, DocumentException {
        // Set content type and header for PDF download
        response.setContentType("application/pdf");
        String headerKey = "Content-Disposition";
        String headerValue = "attachment; filename=insurance_policies_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".pdf";
        response.setHeader(headerKey, headerValue);

        // Fetch all insurance policies from your service
        // உங்களுடைய InsuranceService-ல் உள்ள method-ஐப் பொறுத்து இதை மாற்றவும்
        List<Insurance> allInsurances = insuranceService.getAllInsurancePolicies();

        Document document = new Document();
        PdfWriter.getInstance(document, response.getOutputStream()); // இந்த வரி கண்டிப்பாக இருக்க வேண்டும்
        document.open(); // Correct way to open the document

        // Define a font for the title
        Font titleFont = new Font(Font.FontFamily.HELVETICA, 18, Font.BOLD, BaseColor.BLUE);
        // Define a font for table headers
        Font headerFont = new Font(Font.FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.WHITE);
        // Define a font for table data
        Font dataFont = new Font(Font.FontFamily.HELVETICA, 9, Font.NORMAL, BaseColor.BLACK);


        // Add a title to the PDF
        Paragraph title = new Paragraph("Insurance Policies Report"); // titleFont ஐ பயன்படுத்துங்கள்
//        title.setTextAlignment(Element.ALIGN_CENTER); // Element.ALIGN_CENTER ஐ பயன்படுத்தவும்
//        ((Spaceable) title).setSpacingAfter(20);
//        document.add((Element) title);

        // Create a table for the insurance data
        // நீங்கள் 5 columns உள்ள table ஐ உருவாக்கினீர்கள், ஆனால் data rows-ல் 4 columns மட்டுமே சேர்த்துள்ளீர்கள்.
        // PDF table-ல் நீங்கள் 5 columns காட்ட விரும்பினால், Insurance model-ல் ஒரு 5வது field இருக்க வேண்டும்
        // அல்லது 4 columns ஆக மாற்ற வேண்டும். நான் 5 columns ஆக மாற்றியுள்ளேன், 'Creation Date' ஐ சேர்த்து.
        PdfPTable table = new PdfPTable(4);
        table.setWidthPercentage(100); // Table will take 100% of the page width
        table.setSpacingBefore(10f);
        table.setSpacingAfter(10f);
        // Set relative widths for better column distribution (optional)
        table.setWidths(new float[] {1f, 3f, 3f, 2f}); // 5 columns-க்கு ஏற்ப widths

        // Add table headers
        PdfPCell cell = new PdfPCell();
        cell.setPadding(8); // Increased padding for better appearance
        cell.setBackgroundColor(BaseColor.DARK_GRAY); // Background for header cells
        cell.setHorizontalAlignment(Element.ALIGN_CENTER); // Center align header text

        cell.setPhrase(new Phrase("ID", headerFont));
        table.addCell(cell);
        cell.setPhrase(new Phrase("Name", headerFont));
        table.addCell(cell);
        cell.setPhrase(new Phrase("Coverage", headerFont));
        table.addCell(cell);
        cell.setPhrase(new Phrase("Amount Per Year", headerFont));
        table.addCell(cell);
        // 'Creation Date' column header-ஐ மீண்டும் சேர்க்கவும்
//        cell.setPhrase(new Phrase("Creation Date", headerFont));
//        table.addCell(cell);


        // Add data rows
        // Set cell properties for data rows
        PdfPCell dataCell = new PdfPCell();
        dataCell.setPadding(4);
        dataCell.setHorizontalAlignment(Element.ALIGN_LEFT); // Element.ALIGN_LEFT ஐ பயன்படுத்தவும்

        for (Insurance insurance : allInsurances) {
            // ID
            dataCell.setPhrase(new Phrase(String.valueOf(insurance.getId()), dataFont));
            table.addCell(dataCell);

            // Name
            dataCell.setPhrase(new Phrase(insurance.getName(), dataFont));
            table.addCell(dataCell);

            // Coverage (You had "+ " INR" added here, keeping it as is)
            dataCell.setPhrase(new Phrase(insurance.getCoverage() + " INR", dataFont));
            table.addCell(dataCell);

            // Amount Per Year
            dataCell.setPhrase(new Phrase(String.valueOf(insurance.getAmountPerYear()), dataFont));
            table.addCell(dataCell);

            // Creation Date (assuming Insurance model has getCreationDate() returning LocalDateTime)
//            String creationDateStr = (insurance.getCreationDate() != null) ?
//                                     insurance.getCreationDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "N/A";
//            dataCell.setPhrase(new Phrase(creationDateStr, dataFont));
//            table.addCell(dataCell); // இந்த வரி கட்டாயம் இருக்க வேண்டும்
        }

        document.add(table); // Correct way to add the table to the document
        document.close();    // Correct way to close the document
    }


   
    @GetMapping("/insurance/manageClaims")
    public String manageClaims(HttpSession session, Model model) {
        User loggedInUser = (User) session.getAttribute("loggedInUser");
        if (loggedInUser == null || (!"ADMIN".equals(loggedInUser.getRole()) && !"AGENT".equals(loggedInUser.getRole()))) {
            return "redirect:/login?error=unauthorized";
        }

        List<Claim> allClaims = claimService.getAllClaims(); // <--- Fetch using service
        model.addAttribute("allClaims", allClaims);
        return "admin/manageClaims";
    }

    // --- NEW: Endpoint to update claim status (approve/deny) ---
    @PostMapping("/insurance/updateClaimStatus")
    public String updateClaimStatus(
            @RequestParam("claimId") Long claimId,
            @RequestParam("status") String newStatus,
            @RequestParam(value = "adminNotes", required = false) String adminNotes,
            HttpSession session,
            Model model) {

        User loggedInUser = (User) session.getAttribute("loggedInUser");
        if (loggedInUser == null || (!"ADMIN".equals(loggedInUser.getRole()) && !"AGENT".equals(loggedInUser.getRole()))) {
            return "redirect:/login?error=unauthorized";
        }

        Optional<Claim> claimOpt = claimService.findClaimById(claimId); // <--- Fetch using service
        if (claimOpt.isEmpty()) {
            model.addAttribute("error", "Claim not found.");
            return "redirect:/admin/insurance/manageClaims";
        }

        Claim claim = claimOpt.get();

        // Validate newStatus
        if (!newStatus.equals("APPROVED") && !newStatus.equals("DENIED")) {
            model.addAttribute("error", "Invalid claim status.");
            return "redirect:/admin/insurance/manageClaims";
        }

        claim.setStatus(newStatus);
        claim.setAdminNotes(adminNotes);
        claimService.saveClaim(claim); // <--- Save the updated claim using service

        // ... (Logic for marking BoughtInsurance as claimed, sending emails, etc.)

        model.addAttribute("success", "Claim status updated successfully.");
        return "redirect:/admin/insurance/manageClaims";
    }
    // Payments - Placeholder Endpoints
    @GetMapping("/payments/viewAll")
    public String viewAllPayments(HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // Logic to fetch all payments (Requires new Payment entity, etc.)
            return "admin/viewAllPayments"; // src/main/resources/templates/admin/viewAllPayments.jsp
        }
        return "redirect:/login";
    }

    @GetMapping("/payments/settle")
    public String settlePayments(HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // Logic to settle payments
            return "admin/settlePayments"; // src/main/resources/templates/admin/settlePayments.jsp
        }
        return "redirect:/login";
    }

    // Agents - Placeholder Endpoints
    @GetMapping("/agents/manage")
    public String manageAgents(HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // Logic to manage agents (Requires new Agent entity, etc.)
            return "admin/manageAgents"; // src/main/resources/templates/admin/manageAgents.jsp
        }
        return "redirect:/login";
    }

    @GetMapping("/agents/details")
    public String agentDetails(HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // Logic to view agent details
            return "admin/agentDetails"; // src/main/resources/templates/admin/agentDetails.jsp
        }
        return "redirect:/login";
    }

    // Reports - agentReports.jsp உடன் ஒருங்கிணைக்கப்பட்டது
    @GetMapping("/reports/agent")
    public String agentReports(@RequestParam(value = "year", required = false) Integer year, Model model, HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // தற்போதுள்ள ஆண்டைப் பெற
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            if (year == null) {
                year = currentYear; // ஆண்டு தேர்வு செய்யப்படாவிட்டால், நடப்பு ஆண்டைப் பயன்படுத்தவும்
            }

            List<BoughtInsurance> annualReports = boughtInsuranceService.getBoughtInsurancesByYear(year);
            model.addAttribute("annualReports", annualReports);
            model.addAttribute("selectedYear", year);
            model.addAttribute("currentYear", currentYear); // JSP இல் ஆண்டுகளை உருவாக்க

            return "admin/agentReports"; // src/main/resources/templates/admin/agentReports.jsp
        }
        return "redirect:/login";
    }

    @GetMapping("/reports/insurance")
    public String insuranceReports(HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            // Logic for insurance reports
            return "admin/insuranceReports"; // src/main/resources/templates/admin/insuranceReports.jsp
        }
        return "redirect:/login";
    }
    @GetMapping("/allBoughtInsurances")
    public String viewAllBoughtInsurances(
            @RequestParam(value = "planName", required = false) String planName, // Add this parameter
            HttpSession session,
            Model model) {

        // --- Security Check: Ensure only ADMINs can access this page ---
        User loggedInUser = (User) session.getAttribute("loggedInUser");
        if (loggedInUser == null || !"ADMIN".equals(loggedInUser.getRole())) {
            return "redirect:/login?error=unauthorized";
        }
        // --- End Security Check ---

        List<BoughtInsurance> allBoughtInsurances;

        if (planName != null && !planName.trim().isEmpty()) {
            // If planName is provided, filter the results
            allBoughtInsurances = boughtInsuranceService.getBoughtInsurancesByInsurancePlanName(planName);
            model.addAttribute("planName", planName); // Add planName back to model to retain filter value
        } else {
            // Otherwise, get all bought insurances
            allBoughtInsurances = boughtInsuranceService.getAllBoughtInsurances();
        }

        model.addAttribute("allBoughtInsurances", allBoughtInsurances);
        return "admin/allBoughtInsurancesReport";
    }
    @GetMapping("/reports/allBoughtInsurances/pdf")
    public void generateAllBoughtInsurancesPdf(
            @RequestParam(value = "planName", required = false) String planName, // Add this parameter
            HttpSession session,
            HttpServletResponse response) throws IOException, DocumentException {

        // --- Security Check: Ensure only ADMINs can access this endpoint ---
        User loggedInUser = (User) session.getAttribute("loggedInUser");
        if (loggedInUser == null || !"ADMIN".equals(loggedInUser.getRole())) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied: Only administrators can generate this report.");
            return;
        }
        // --- End Security Check ---

        List<BoughtInsurance> allBoughtInsurances;
        if (planName != null && !planName.trim().isEmpty()) {
            allBoughtInsurances = boughtInsuranceService.getBoughtInsurancesByInsurancePlanName(planName);
        } else {
            allBoughtInsurances = boughtInsuranceService.getAllBoughtInsurances();
        }

        response.setContentType("application/pdf");
        String filename = (planName != null && !planName.trim().isEmpty()) ?
                          "Bought_Insurances_Report_" + planName.replaceAll(" ", "_") + ".pdf" :
                          "All_Bought_Insurances_Report.pdf";
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");


        Document document = new Document();
        PdfWriter.getInstance(document, response.getOutputStream());
        document.open();

        Font titleFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 20, BaseColor.BLUE);
        Font headerFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 12, BaseColor.WHITE);
        Font normalFont = FontFactory.getFont(FontFactory.HELVETICA, 10, BaseColor.BLACK);

        Paragraph title = new Paragraph("All Bought Insurance Policies Report");
        

        if (planName != null && !planName.trim().isEmpty()) {
            Paragraph filterInfo = new Paragraph("Filtered by Plan: " + planName);
            
        }


        PdfPTable table = new PdfPTable(8); // Adjust column count as per details you want to show
        table.setWidthPercentage(100);
        table.setSpacingBefore(10f);
        table.setWidths(new float[]{1.0f, 2.0f, 1.5f, 1.0f, 1.5f, 1.5f, 1.5f, 1.5f}); // Adjust column widths

        // Table Headers
        String[] headers = {"Policy No.", "Customer Name", "Insurance Plan", "Premium", "Coverage", "Purchase Date", "Expiry Date", "Email"};
        for (String header : headers) {
            PdfPCell cell = new PdfPCell(new Phrase(header, headerFont));
            cell.setBackgroundColor(BaseColor.DARK_GRAY);
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
            cell.setPadding(5);
            table.addCell(cell);
        }

        // Table Data
        if (allBoughtInsurances != null && !allBoughtInsurances.isEmpty()) {
            DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
            for (BoughtInsurance policy : allBoughtInsurances) {
                table.addCell(new Phrase(policy.getPolicyNumber(), normalFont));
                table.addCell(new Phrase(policy.getName(), normalFont)); // Customer Name
                table.addCell(new Phrase(policy.getInsurance().getName(), normalFont)); // Insurance Plan Name
                table.addCell(new Phrase(String.format("₹%.2f", policy.getInsurance().getAmountPerYear()), normalFont));
                table.addCell(new Phrase(String.format("₹%.2f", policy.getInsurance().getCoverage()), normalFont));

                // Date formatting for purchase and expiry dates
                String purchaseDateStr = (policy.getPurchaseDate() != null) ?
                        policy.getPurchaseDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(dateFormatter) : "N/A";
                table.addCell(new Phrase(purchaseDateStr, normalFont));

                String expiryDateStr = (policy.getExpiryDate() != null) ?
                        policy.getExpiryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(dateFormatter) : "N/A";
                table.addCell(new Phrase(expiryDateStr, normalFont));
                table.addCell(new Phrase(policy.getEmail(), normalFont));
            }
        } else {
            PdfPCell noDataCell = new PdfPCell(new Phrase("No bought insurance policies found matching the filter.", normalFont));
            noDataCell.setColspan(8); // Span across all columns
            noDataCell.setHorizontalAlignment(Element.ALIGN_CENTER);
            noDataCell.setPadding(10);
            table.addCell(noDataCell);
        }

        document.add(table);
        document.close();
    }
    @GetMapping("/reports/allBoughtInsurances/excel")
    public void generateAllBoughtInsurancesExcel(
            @RequestParam(value = "planName", required = false) String planName, // Add this parameter
            HttpSession session,
            HttpServletResponse response) throws IOException {

        // --- Security Check: Ensure only ADMINs can access this endpoint ---
        User loggedInUser = (User) session.getAttribute("loggedInUser");
        if (loggedInUser == null || !"ADMIN".equals(loggedInUser.getRole())) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied: Only administrators can generate this report.");
            return;
        }
        // --- End Security Check ---

        List<BoughtInsurance> allBoughtInsurances;
        if (planName != null && !planName.trim().isEmpty()) {
            allBoughtInsurances = boughtInsuranceService.getBoughtInsurancesByInsurancePlanName(planName);
        } else {
            allBoughtInsurances = boughtInsuranceService.getAllBoughtInsurances();
        }

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        String filename = (planName != null && !planName.trim().isEmpty()) ?
                          "Bought_Insurances_Report_" + planName.replaceAll(" ", "_") + ".xlsx" :
                          "All_Bought_Insurances_Report.xlsx";
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

        // Use Apache POI for Excel generation
        try (Workbook workbook = new XSSFWorkbook()) { // Use interface for consistency
            Sheet sheet = workbook.createSheet("Bought Insurances");

            // Create Header Row
            Row headerRow = sheet.createRow(0);
            String[] headers = {"Policy Number", "Customer Name", "Customer DOB", "Customer Address", "Customer Phone", "Customer Email", "Insurance Plan", "Coverage", "Premium", "Purchase Date", "Expiry Date"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }

            // Populate Data Rows
            int rowNum = 1;
            DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

            for (BoughtInsurance policy : allBoughtInsurances) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(policy.getPolicyNumber());
                row.createCell(1).setCellValue(policy.getName()); // Customer Name
                row.createCell(2).setCellValue(policy.getDob() != null ? policy.getDob().format(dateFormatter) : "N/A"); // Customer DOB
                row.createCell(3).setCellValue(policy.getAddress()); // Customer Address
                row.createCell(4).setCellValue(policy.getPhone()); // Customer Phone
                row.createCell(5).setCellValue(policy.getEmail()); // Customer Email
                row.createCell(6).setCellValue(policy.getInsurance().getName()); // Insurance Plan Name
                row.createCell(7).setCellValue(policy.getInsurance().getCoverage());
                row.createCell(8).setCellValue(policy.getInsurance().getAmountPerYear());

                String purchaseDateStr = (policy.getPurchaseDate() != null) ?
                        policy.getPurchaseDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(dateFormatter) : "N/A";
                row.createCell(9).setCellValue(purchaseDateStr);

                String expiryDateStr = (policy.getExpiryDate() != null) ?
                        policy.getExpiryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(dateFormatter) : "N/A";
                row.createCell(10).setCellValue(expiryDateStr);
            }

            // Auto-size columns for better readability
            for (int i = 0; i < headers.length; i++) {
                sheet.autoSizeColumn(i);
            }

            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            System.err.println("Error generating Excel report: " + e.getMessage());
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error generating Excel report.");
        }
    }

    @GetMapping("/reports/user")
    public String userReports(Model model, HttpSession session) {
        Long userId = (Long) session.getAttribute("userId");
        if (userId != null && "ADMIN".equals(userService.findUserById(userId).get().getRole())) {
            List<User> users = userService.getAllUsers();
            // ஒவ்வொரு பயனருக்கும் அவர்களின் வாங்கிய காப்பீடுகளைச் சேமிக்க ஒரு வரைபடத்தை உருவாக்கவும்
            Map<User, List<BoughtInsurance>> userBoughtInsurances = new LinkedHashMap<>();
            for (User user : users) {
                List<BoughtInsurance> boughtInsurances = boughtInsuranceService.getBoughtInsuranceByUser(user);
                userBoughtInsurances.put(user, boughtInsurances);
            }
            model.addAttribute("userBoughtInsurances", userBoughtInsurances);
            return "admin/userReports"; // src/main/resources/templates/admin/userReports.jsp
        }
        return "redirect:/login";
    }

    @GetMapping("/reports/claim")
    public String claimReports(HttpSession session, Model model,
                               @RequestParam(name = "insuranceName", required = false) String insuranceName) {
        Long userId = (Long) session.getAttribute("userId");
        System.out.println("Accessing /reports/claim. User ID: " + userId);
        if (userId != null) {
            Optional<User> userOptional = userService.findUserById(userId);
            if (userOptional.isPresent()) {
                User user = userOptional.get();
                System.out.println("User role: " + user.getRole());
                if ("ADMIN".equals(user.getRole())) {
                    // ... your existing claim fetching logic ...
                    List<Claim> claimedInsurances;
                    if (insuranceName != null && !insuranceName.isEmpty()) {
                        claimedInsurances = claimService.findClaimedInsurancesByName(insuranceName);
                        System.out.println("Claims fetched by name. Count: " + claimedInsurances.size());
                    } else {
                        claimedInsurances = claimService.getAllClaims();
                        System.out.println("All claims fetched. Count: " + claimedInsurances.size());
                    }
                    model.addAttribute("claimedInsurances", claimedInsurances);
                    model.addAttribute("currentFilter", insuranceName);
                    return "admin/claimReports";
                }
            }
        }
        System.out.println("Redirecting to login: User not found or not ADMIN.");
        return "redirect:/login";
    }
    
    @GetMapping("/reports/claim/download-all-pdf")
    public ResponseEntity<InputStreamResource> downloadAllClaimsPdf(
            @RequestParam(name = "insuranceName", required = false) String insuranceName) {
        // Logic to fetch all claims, potentially filtered by insuranceName
        List<Claim> claims;
        if (insuranceName != null && !insuranceName.isEmpty()) {
            claims = claimService.findClaimedInsurancesByName(insuranceName); // You need this method in ClaimService
        } else {
            claims = claimService.findAllClaimedInsurances();
        }

        // Call a service method to generate PDF
        byte[] bis = pdfGeneratorService.generateClaimPdf(claims); // Create this service

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "inline; filename=all_claim_reports.pdf");

        return ResponseEntity
                .ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_PDF).body(new InputStreamResource(new ByteArrayInputStream(bis)));
                
    }
    
//    @GetMapping("/reports/claim/send-all-email") // No {claimId} here
//    public String sendAllClaimsEmail(
//            @RequestParam(name = "insuranceName", required = false) String insuranceName, // Receive filter as @RequestParam
//            HttpSession session,
//            RedirectAttributes redirectAttributes) { // Use RedirectAttributes for messages
//
//        Long userId = (Long) session.getAttribute("userId");
//        if (userId == null) {
//            // User is not logged in
//            return "redirect:/login";
//        }
//
//        Optional<User> userOptional = userService.findUserById(userId);
//        if (userOptional.isEmpty() || !"ADMIN".equals(userOptional.get().getRole())) {
//            // User not found or not an admin
//            return "redirect:/login"; // Or an access denied page
//        }
//
//        List<Claim> claims;
//        if (insuranceName != null && !insuranceName.isEmpty()) {
//            claims = claimService.findClaimedInsurancesByName(insuranceName);
//            // Ensure you have a method like this in your ClaimService that takes a filter
//            // e.g., public List<Claim> findClaimedInsurancesByName(String insuranceName) { ... }
//        } else {
//            claims = claimService.findAllClaimedInsurances();
//        }
//
//        if (claims.isEmpty()) {
//            redirectAttributes.addFlashAttribute("error", "No claims found to send report for.");
//            return "redirect:/admin/reports/claim" + (insuranceName != null && !insuranceName.isEmpty() ? "?insuranceName=" + insuranceName : "");
//        }
//
//        try {
//            // You need to decide how to generate the PDF for ALL claims.
//            // Option 1: Generate one big PDF for all claims.
//            byte[] pdfBytes = pdfGeneratorService.generateClaimPdf(claims); // This method should generate a multi-claim PDF
//
//            // Option 2: Loop and send individual emails (less likely for "send all" button)
//            // for (Claim claim : claims) {
//            //    byte[] individualPdf = pdfGeneratorService.generateClaimPdf(claim);
//            //    emailService.sendEmailWithAttachment("recipient@example.com", "Claim Report for " + claim.getClaimNumber(), "...", individualPdf, "claim_" + claim.getId() + ".pdf", MediaType.APPLICATION_PDF_VALUE);
//            // }
//
//            String toEmail = "manickaraj1516@gmail.com"; // Consider making this configurable or user-selectable
//            String subject = "Comprehensive Claims Report" + (insuranceName != null && !insuranceName.isEmpty() ? " (Filtered by: " + insuranceName + ")" : "");
//            String body = "Dear Admin,\n\nPlease find the attached PDF report containing details of " + claims.size() + " claims" + (insuranceName != null && !insuranceName.isEmpty() ? " filtered by insurance name: " + insuranceName : "") + ".\n\nRegards,\nYour Healthcare System";
//            String attachmentName = "claims_report" + (insuranceName != null && !insuranceName.isEmpty() ? "_" + insuranceName.replace(" ", "_") : "") + ".pdf";
//            String attachmentContentType = MediaType.APPLICATION_PDF_VALUE;
//
//            emailService.sendEmailWithAttachment(toEmail, subject, body, pdfBytes, attachmentName, attachmentContentType);
//            redirectAttributes.addFlashAttribute("message", "Claims report email sent successfully for " + claims.size() + " claims!");
//        } catch (Exception e) {
//            redirectAttributes.addFlashAttribute("error", "Failed to send claims report email. Error: " + e.getMessage());
//            e.printStackTrace(); // Log the error for debugging
//        }
//
//        // Redirect back to the claim reports page, maintaining the filter if present
//        return "redirect:/admin/reports/claim" + (insuranceName != null && !insuranceName.isEmpty() ? "?insuranceName=" + insuranceName : "");
//    }
    @GetMapping("/reports/claim/send-all-email") // No {claimId} here
    public String sendAllClaimsEmail(
            @RequestParam(name = "insuranceName", required = false) String insuranceName, // Receive filter as @RequestParam
            HttpSession session,
            RedirectAttributes redirectAttributes) { // Use RedirectAttributes for messages

        Long userId = (Long) session.getAttribute("userId");
        log.info("Accessing /reports/claim/send-all-email. User ID: {}", userId);
        if (userId == null) {
            // User is not logged in
            return "redirect:/login";
        }

        Optional<User> userOptional = userService.findUserById(userId);
        if (userOptional.isEmpty() || !"ADMIN".equals(userOptional.get().getRole())) {
            // User not found or not an admin
            return "redirect:/login"; // Or an access denied page
        }

        List<Claim> claims;
        if (insuranceName != null && !insuranceName.isEmpty()) {
        	log.info("Filtering by insuranceName: " + insuranceName);
        	claims = claimService.findClaimedInsurancesByName(insuranceName);
            // Ensure you have a method like this in your ClaimService that takes a filter
            // e.g., public List<Claim> findClaimedInsurancesByName(String insuranceName) { ... }
        } else {
        	log.info("Fetching all claims (no insuranceName filter).");
            claims = claimService.findAllClaimedInsurances();
        }

        if (claims.isEmpty()) {
            redirectAttributes.addFlashAttribute("error", "No claims found to send report for.");
            return "redirect:/admin/reports/claim" + (insuranceName != null && !insuranceName.isEmpty() ? "?insuranceName=" + insuranceName : "");
        }

        try {
            // You need to decide how to generate the PDF for ALL claims.
            // Option 1: Generate one big PDF for all claims.
            byte[] pdfBytes = pdfGeneratorService.generateClaimPdf(claims); // This method should generate a multi-claim PDF

            // Option 2: Loop and send individual emails (less likely for "send all" button)
            // for (Claim claim : claims) {
            //    byte[] individualPdf = pdfGeneratorService.generateClaimPdf(claim);
            //    emailService.sendEmailWithAttachment("recipient@example.com", "Claim Report for " + claim.getClaimNumber(), "...", individualPdf, "claim_" + claim.getId() + ".pdf", MediaType.APPLICATION_PDF_VALUE);
            // }

            String toEmail = "manickaraj1516@gmail.com"; // Consider making this configurable or user-selectable
            String subject = "Comprehensive Claims Report" + (insuranceName != null && !insuranceName.isEmpty() ? " (Filtered by: " + insuranceName + ")" : "");
            String body = "Dear Admin,\n\nPlease find the attached PDF report containing details of " + claims.size() + " claims" + (insuranceName != null && !insuranceName.isEmpty() ? " filtered by insurance name: " + insuranceName : "") + ".\n\nRegards,\nYour Healthcare System";
            String attachmentName = "claims_report" + (insuranceName != null && !insuranceName.isEmpty() ? "_" + insuranceName.replace(" ", "_") : "") + ".pdf";
            String attachmentContentType = MediaType.APPLICATION_PDF_VALUE;

            emailService.sendEmailWithAttachment(toEmail, subject, body, pdfBytes, attachmentName, attachmentContentType);
            redirectAttributes.addFlashAttribute("message", "Claims report email sent successfully for " + claims.size() + " claims!");
        } catch (Exception e) {
            redirectAttributes.addFlashAttribute("error", "Failed to send claims report email. Error: " + e.getMessage());
            e.printStackTrace(); // Log the error for debugging
        }

        // Redirect back to the claim reports page, maintaining the filter if present
        return "redirect:/admin/reports/claim" + (insuranceName != null && !insuranceName.isEmpty() ? "?insuranceName=" + insuranceName : "");
    }
}
