package com.cos.bean;

import com.cos.entity.CertificateOfSponsorship;
import com.cos.service.CosService;
import com.cos.service.PdfGenerationService;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * JSF Backing Bean for the Certificate of Sponsorship form.
 * Handles form submission, validation, database persistence,
 * and PDF generation via Apache FOP 2.3.
 */
@Named("cosFormBean")
@ViewScoped
public class CosFormBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = Logger.getLogger(CosFormBean.class.getName());

    @Inject
    private CosService cosService;

    @Inject
    private PdfGenerationService pdfGenerationService;

    // ─── Form Model ──────────────────────────────────────────────────────────────
    private CertificateOfSponsorship cos;

    // ─── UI State ────────────────────────────────────────────────────────────────
    private List<CertificateOfSponsorship> allRecords;
    private boolean formSubmitted = false;
    private boolean editMode = false;
    private String activeTab = "form";

    // ─── Dropdown Options ────────────────────────────────────────────────────────
    private List<String> tierCategories;
    private List<String> certStatusOptions;
    private List<String> genderOptions;
    private List<String> yesNoOptions;
    private List<String> salaryPeriodOptions;
    private List<String> countryOptions;

    @PostConstruct
    public void init() {
        cos = new CertificateOfSponsorship();
        loadDropdownOptions();
        loadAllRecords();
        prefillFromPdf();
    }

    /**
     * Pre-fill the form with data from the uploaded PDF for demonstration.
     */
    private void prefillFromPdf() {
        cos.setTierAndCategory("Skilled Worker (Switching immigration category - ISC liable)");
        cos.setSponsorLicenceNumber("08RNFHNMX");
        cos.setSponsorName("MG MAGNA WHOLESALE AND RETAIL LIMITED");
        cos.setCertificateNumber("C2G8X39142K");
        cos.setCurrentCertStatus("ASSIGNED");
        cos.setCurrentCertStatusDate(LocalDate.of(2026, 1, 11));
        cos.setDateAssigned(LocalDate.of(2026, 1, 11));
        cos.setExpiryDateUseBy(LocalDate.of(2026, 4, 12));
        cos.setSponsorshipWithdrawn("N");
        cos.setSponsorNote("Work start and end dates updated as follows: Start date: 16/02/2026 End date: 15/12/2026");
        cos.setFamilyName("-");
        cos.setGivenNames("Priya");
        cos.setNationality("INDIA");
        cos.setPlaceOfBirth("Gundiana, Haryana");
        cos.setCountryOfBirth("INDIA");
        cos.setDateOfBirth(LocalDate.of(2000, 8, 2));
        cos.setGender("Female");
        cos.setCountryOfResidence("UNITED KINGDOM");
        cos.setPassportNumber("V1692834");
        cos.setPassportIssueDate(LocalDate.of(2021, 8, 17));
        cos.setPassportExpiryDate(LocalDate.of(2031, 8, 16));
        cos.setPlaceOfIssuePassport("Chandigarh");
        cos.setHomeAddress("33 Hunter Road");
        cos.setHomeCityTown("Leicester");
        cos.setHomePostcode("LE4 5GJ");
        cos.setHomeCountry("UNITED KINGDOM");
        cos.setUkNationalInsuranceNumber("TL726486C");
        cos.setWorkStartDate(LocalDate.of(2026, 2, 3));
        cos.setWorkEndDate(LocalDate.of(2028, 2, 4));
        cos.setLeaveReenterUk("N");
        cos.setTotalWeeklyHours(37.50);
        cos.setWorkAddress("5-7 Canal Street");
        cos.setWorkCityTown("Leicester");
        cos.setWorkPostcode("LE18 4PL");
        cos.setJobTitle("Purchase Manager");
        cos.setJobType("1134 Purchasing managers and directors");
        cos.setJobDescription("Responsible for sourcing and purchasing the best quality materials. " +
                "Build and maintain good relationships with suppliers. " +
                "Support product change requests and review and communicate this with relevant people. " +
                "Establish market trend for material availability. " +
                "Ensure the security and sustainability of sources for essential materials. " +
                "Set, monitor, and review stock levels and adjust these if required. " +
                "Proactively contribute to creating a working environment for team. " +
                "Liaise between suppliers, manufacturers and internal teams ensuring business needs are met. " +
                "Meet with suppliers to negotiate prices and discuss any issues. " +
                "Researches and identifies new products and suppliers.");
        cos.setNewEntrant("Y");
        cos.setGrossSalary(38500.00);
        cos.setSalaryPeriod("Year");
        cos.setAppropriateSkillLevel("Y");
        cos.setCertifyMaintenance("Y");
        cos.setAtasRequired("N");
        cos.setPayeReferenceSupplied("Y");
        cos.setPayeReferenceNumber("120/XE88989");
        cos.setPhdLevelRequired("N");
    }

    /**
     * Initialize dropdown option lists.
     */
    private void loadDropdownOptions() {
        tierCategories = Arrays.asList(
            "Skilled Worker",
            "Skilled Worker (Switching immigration category - ISC liable)",
            "Skilled Worker (New Entrant)",
            "Intra-Company Transfer",
            "Intra-Company Graduate Trainee",
            "Senior or Specialist Worker",
            "Graduate Trainee",
            "UK Expansion Worker",
            "Scale-up Worker",
            "Seasonal Worker",
            "Creative Worker",
            "Charity Worker",
            "Religious Worker",
            "Government Authorised Exchange",
            "International Agreement",
            "Minister of Religion",
            "Sportsperson"
        );

        certStatusOptions = Arrays.asList(
            "ASSIGNED", "UNASSIGNED", "EXPIRED", "WITHDRAWN", "USED"
        );

        genderOptions = Arrays.asList("Male", "Female", "Other", "Prefer not to say");

        yesNoOptions = Arrays.asList("Y", "N");

        salaryPeriodOptions = Arrays.asList("Year", "Month", "Week", "Hour");

        countryOptions = Arrays.asList(
            "UNITED KINGDOM", "INDIA", "PAKISTAN", "BANGLADESH", "NIGERIA",
            "PHILIPPINES", "CHINA", "UNITED STATES", "CANADA", "AUSTRALIA",
            "SOUTH AFRICA", "KENYA", "GHANA", "ZIMBABWE", "NEPAL",
            "SRI LANKA", "MALAYSIA", "SINGAPORE", "BRAZIL", "FRANCE",
            "GERMANY", "ITALY", "SPAIN", "POLAND", "ROMANIA", "OTHER"
        );
    }

    /**
     * Load all CoS records from the database.
     */
    public void loadAllRecords() {
        allRecords = cosService.findAll();
    }

    /**
     * Save the form data to the database.
     */
    public String saveForm() {
        try {
            CertificateOfSponsorship saved = cosService.saveOrUpdate(cos);
            cos = saved;
            formSubmitted = true;
            loadAllRecords();
            addMessage(FacesMessage.SEVERITY_INFO,
                    "Success",
                    "Certificate of Sponsorship saved successfully! ID: " + saved.getId());
            LOGGER.info("CoS saved with ID: " + saved.getId());
            return null;
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Error saving CoS", e);
            addMessage(FacesMessage.SEVERITY_ERROR,
                    "Error",
                    "Failed to save: " + e.getMessage());
            return null;
        }
    }

    /**
     * Generate and download the PDF using Apache FOP 2.3.
     */
    public void downloadPdf() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();

        try {
            // Ensure the record is saved first
            if (cos.getId() == null) {
                cosService.saveOrUpdate(cos);
            }

            // Generate PDF bytes via FOP
            byte[] pdfBytes = pdfGenerationService.generatePdf(cos);

            // Set HTTP response headers for PDF download
            String filename = "CoS_" + cos.getCertificateNumber() + ".pdf";
            externalContext.responseReset();
            externalContext.setResponseContentType("application/pdf");
            externalContext.setResponseContentLength(pdfBytes.length);
            externalContext.setResponseHeader("Content-Disposition",
                    "attachment; filename=&quot;" + filename + "&quot;");
            externalContext.setResponseHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            externalContext.setResponseHeader("Pragma", "no-cache");
            externalContext.setResponseHeader("Expires", "0");

            // Write PDF to response output stream
            OutputStream responseOutputStream = externalContext.getResponseOutputStream();
            responseOutputStream.write(pdfBytes);
            responseOutputStream.flush();

            facesContext.responseComplete();
            LOGGER.info("PDF generated and sent for CoS: " + cos.getCertificateNumber());

        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "IO Error generating PDF", e);
            addMessage(FacesMessage.SEVERITY_ERROR, "PDF Error",
                    "Failed to generate PDF: " + e.getMessage());
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Error generating PDF", e);
            addMessage(FacesMessage.SEVERITY_ERROR, "PDF Error",
                    "Failed to generate PDF: " + e.getMessage());
        }
    }

    /**
     * Load a CoS record for editing.
     */
    public void editRecord(Long id) {
        cosService.findById(id).ifPresent(record -> {
            cos = record;
            editMode = true;
            activeTab = "form";
        });
    }

    /**
     * Delete a CoS record.
     */
    public void deleteRecord(Long id) {
        try {
            cosService.delete(id);
            loadAllRecords();
            addMessage(FacesMessage.SEVERITY_INFO, "Deleted", "Record deleted successfully.");
        } catch (Exception e) {
            addMessage(FacesMessage.SEVERITY_ERROR, "Error", "Failed to delete: " + e.getMessage());
        }
    }

    /**
     * Reset the form to a new blank CoS.
     */
    public void resetForm() {
        cos = new CertificateOfSponsorship();
        formSubmitted = false;
        editMode = false;
    }

    /**
     * Download PDF for a specific record from the list.
     */
    public void downloadPdfForRecord(Long id) {
        cosService.findById(id).ifPresent(record -> {
            cos = record;
            downloadPdf();
        });
    }

    // ─── Helper ──────────────────────────────────────────────────────────────────
    private void addMessage(FacesMessage.Severity severity, String summary, String detail) {
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(severity, summary, detail));
    }

    // ─── Getters & Setters ───────────────────────────────────────────────────────
    public CertificateOfSponsorship getCos() { return cos; }
    public void setCos(CertificateOfSponsorship cos) { this.cos = cos; }

    public List<CertificateOfSponsorship> getAllRecords() { return allRecords; }

    public boolean isFormSubmitted() { return formSubmitted; }
    public void setFormSubmitted(boolean formSubmitted) { this.formSubmitted = formSubmitted; }

    public boolean isEditMode() { return editMode; }
    public void setEditMode(boolean editMode) { this.editMode = editMode; }

    public String getActiveTab() { return activeTab; }
    public void setActiveTab(String activeTab) { this.activeTab = activeTab; }

    public List<String> getTierCategories() { return tierCategories; }
    public List<String> getCertStatusOptions() { return certStatusOptions; }
    public List<String> getGenderOptions() { return genderOptions; }
    public List<String> getYesNoOptions() { return yesNoOptions; }
    public List<String> getSalaryPeriodOptions() { return salaryPeriodOptions; }
    public List<String> getCountryOptions() { return countryOptions; }
}