<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
        <funnelHeader
            cmsWidgetName="FunnelHeaderWidget"
            ref="funnelHeader"
            :overrideImageSrc="clientLogoImageSrc" />
        <div class="container">
            <div class="row">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <funnelSubHeader
                        cmsWidgetName="FunnelSubHeaderWidget"
                        class="siteSubHeader pb-4"
                        :alignLeft="true"
                        :overrideHeaderText="subHeaderTextOverride"
                        :overrideHeaderSubText="subHeaderSubTextOverride" />

                    <textboxQuestion
                        isRequired
                        class="mb-1"
                        cmsWidgetName="PolicyNumberWidget"
                        :overrideQuestionText="policyNumberLabelOverride"
                        v-model="policyNumber"
                        inputId="policyNumber"
                        validationRules="policy-number-required|policy-number-format" />
                    <span
                        v-if="displayPolicyHelperText"
                        class="d-block mb-5 helper-text"
                        v-html="policyHelperText"></span>

                    <datePickerPopup
                        v-if="displayDateOfBirth"
                        isRequired
                        class="mb-4"
                        cmsWidgetName="DateOfBirthWidget"
                        v-model="dateOfBirth"
                        customInputId="dateOfBirth"
                        placeholderText="MM/DD/YYYY"
                        validationRules="date-of-birth-required"
                        format="MM/dd/yyyy"
                        modelType="yyyy-MM-dd"
                        :enableTimePicker="false"
                        :textInput="true"
                        :maxDate="today"
                        :preventMinMaxNavigation="true" />

                    <textboxQuestion
                        v-if="displayLastName"
                        isRequired
                        class="mb-4"
                        cmsWidgetName="LastNameWidget"
                        v-model="lastName"
                        inputId="lastName"
                        validationRules="last-name-required" />

                    <textboxQuestion
                        v-if="displayStreetAddress"
                        isRequired
                        class="mb-4"
                        cmsWidgetName="StreetAddressWidget"
                        v-model="streetAddress"
                        inputId="streetAddress"
                        validationRules="street-address-required" />

                    <textboxQuestion
                        isRequired
                        class="mb-4"
                        cmsWidgetName="ZipWidget"
                        v-model="policyZip"
                        inputId="policyZip"
                        maxLength="5"
                        validationRules="zip-code-required|zip-code-format" />

                    <div class="row">
                        <div class="col-12 col-md-8">
                            <textboxQuestion
                                isRequired
                                class="mb-4"
                                cmsWidgetName="PhoneWidget"
                                v-model="phoneNumber"
                                inputId="phoneNumber"
                                mask="###-###-####"
                                validationRules="phone-number-required" />
                        </div>
                        <div class="col-12 col-md-4">
                            <textboxQuestion
                                isRequired
                                class="mb-4"
                                cmsWidgetName="PhoneExtensionWidget"
                                v-model="phoneExtension"
                                inputId="phoneExtension"
                                maxLength="5"
                                validationRules="phone-extension-format" />
                        </div>
                    </div>

                    <datePickerPopup
                        isRequired
                        class="mb-4"
                        cmsWidgetName="DateOfLossWidget"
                        v-model="dateOfLoss"
                        customInputId="dateOfLoss"
                        placeholderText="MM/DD/YYYY"
                        validationRules="date-of-loss-required"
                        format="MM/dd/yyyy"
                        modelType="yyyy-MM-dd"
                        :enableTimePicker="false"
                        :textInput="true"
                        :maxDate="today"
                        :preventMinMaxNavigation="true" />

                    <dropdownQuestion
                        v-if="displayLossTime"
                        isRequired
                        :questionText="timeOfLossQuestionText"
                        class="mb-4"
                        v-model="lossTime"
                        cmsWidgetName="TimeOfLossWidget"
                        customDropdownId="lossTime"
                        :options="lossTimeOptions"
                        :valueAsKey="true"
                        validationRules="loss-time-required"
                        :labelBold="true" />

                    <dropdownQuestion
                        isRequired
                        :questionText="damageTypesQuestionText"
                        class="mb-4"
                        v-model="damageCause"
                        cmsWidgetName="DamageTypesWidget"
                        customDropdownId="damageTypes"
                        :options="damageTypesOptions"
                        :valueAsKey="true"
                        validationRules="damage-types-required"
                        :labelBold="true" />

                    <buttonQuestion
                        v-if="displaySubrogation"
                        :questionText="subrogationQuestionText"
                        :answers="subrogationAnswers"
                        class="mb-4"
                        groupName="SubrogationQuestion"
                        buttonTypeString="listButton"
                        isRequired
                        validationRules="subrogation-required"
                        v-model="subrogationSelectedValue" />

                    <dropdownQuestion
                        v-if="displayLossState"
                        class="mb-4"
                        customDropdownId="policyState"
                        cmsWidgetName="StateQuestionWidget"
                        v-model="policyState"
                        ref="policyState"
                        :options="stateOptions"
                        validationRules="state-required"
                        autocomplete="address-level1"
                        placeHolderText="Select State"
                        :labelBold="true" />

                    <dropdownQuestion
                        v-if="displayLossLocation"
                        :questionText="lossLocationQuestionText"
                        class="mb-4"
                        v-model="lossLocation"
                        cmsWidgetName="LossLocationQuestionWidget"
                        customDropdownId="lossLocation"
                        :options="lossLocationOptions"
                        :valueAsKey="true"
                        validationRules="loss-location-required"
                        :labelBold="true" />

                    <textboxQuestion
                        v-if="displayLossCity"
                        isRequired
                        class="mb-4"
                        cmsWidgetName="CityWidget"
                        v-model="city"
                        inputId="city"
                        validationRules="city-required" />

                    <hr class="mt-4 mb-0" />

                    <morePolicyQuestions
                        ref="morePolicyQuestions"
                        class="mb-4"
                        :cmsWidgetName="morePolicyQuestionsWidgetName"
                        v-model="morePolicyQuestions"
                        groupName="MorePolicyQuestionsQuestion" />

                    <textboxQuestion
                        v-if="displayClaimNumber"
                        isRequired
                        class="mb-4"
                        cmsWidgetName="ClaimNumberWidget"
                        v-model="claimNumber"
                        inputId="claimNumber"
                        validationRules="claim-number-required" />

                    <insuranceNavBar
                        cmsWidgetName="FunnelFooterWidget"
                        ref="navbar"
                        :isForwardActionDisabled="!meta.valid"
                        isBackButtonHidden
                        @cancel-clicked="cancelButtonAction"
                        @ForwardClicked="forwardButtonAction" />

                    <span
                        v-if="displayDisclaimerText"
                        class="d-block mb-5 disclaimer-text"
                        v-html="disclaimerText"></span>
                </div>
            </div>
        </div>
    </Form>
</template>

<script>
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import insuranceNavBar from "@/fmg-components/insurance-nav-bar/insurance-nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import datePickerPopup from "@/digital-components/date-picker-popup/date-picker-popup";
import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-question";
import morePolicyQuestions from "@/layouts/policy-info/more-policy-questions/more-policy-questions";
import buttonQuestion from "@/digital-components/button-question/button-question";
import { stateOptions } from "@/constants/state-options";
import {
    morePolicyQuestionAnswers,
    morePolicyQuestionAnswerToFlag,
} from "@/constants/more-policy-questions";
import { Form, defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import { regex } from "@/helpers/validation-rules";

import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import store from "@/store";
import { debugLog } from "@/helpers/debug-log-helper";

// The PolicyNumberValidationWidget is fetched asynchronously from the CMS (see
// beforeRouteEnter below), so the format rule reads it from this module-scoped
// reference rather than capturing a value at defineRule time.
let policyNumberValidationConfig = null;

function getPolicyNumberFormatPattern(validationRuleType) {
    switch ((validationRuleType || "").toLowerCase()) {
        case "alpha":
            return /^[A-Za-z]+$/;
        case "numeric":
            return /^[0-9]+$/;
        case "alphanumeric":
            return /^[A-Za-z0-9]+$/;
        case "alphanumericwithspaces":
            return /^[A-Za-z0-9 ]+$/;
        default:
            return null;
    }
}

// Like ConfigWidget, PolicyNumberValidationWidget's actual config comes back from the CMS
// as a JSON-encoded string in its `Text` property, not as a plain object.
// examples:
/* {
        "minimumLength": 1,
        "maximumLength": 16,
        "validationRuleType": "AlphaNumeric",
        "minValidationMessage": "",
        "maxValidationMessage": "That looks like a VIN. Your policy number should be 16 characters maximum.",
        "invalidCharMessage": "Policy number must be numbers and letters only."
    }
    {
        "minimumLength": 8,
        "maximumLength": 9,
        "validationRuleType": "AlphaNumeric",
        "minValidationMessage": "Policy number should be at least 8 characters.",
        "maxValidationMessage": "Policy number must be 9 characters or less."
    }
*/
function parsePolicyNumberValidationWidget(widget) {
    const raw = widget?.Text;
    if (!raw) {
        return null;
    }
    try {
        return JSON.parse(raw);
    } catch (err) {
        console.warn("Failed to parse PolicyNumberValidationWidget.Text", err);
        return null;
    }
}

defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED));
defineRule("policy-number-format", (value) => {
    if (!value || !value.length || !policyNumberValidationConfig) {
        return true;
    }

    const {
        minimumLength,
        maximumLength,
        validationRuleType,
        minValidationMessage,
        maxValidationMessage,
        invalidCharMessage,
    } = policyNumberValidationConfig;

    if (typeof minimumLength === "number" && value.length < minimumLength) {
        return minValidationMessage || errorMessages.POLICY_NUMBER_FORMAT;
    }

    if (typeof maximumLength === "number" && value.length > maximumLength) {
        return maxValidationMessage || errorMessages.POLICY_NUMBER_FORMAT;
    }

    const pattern = getPolicyNumberFormatPattern(validationRuleType);
    if (pattern && !pattern.test(value)) {
        return invalidCharMessage || errorMessages.POLICY_NUMBER_FORMAT;
    }

    return true;
});
defineRule("zip-code-required", required(errorMessages.ZIP_REQUIRED));
defineRule("zip-code-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.ZIP_FORMAT));
defineRule("phone-number-required", required(errorMessages.PHONE_REQUIRED));
defineRule("phone-extension-format", regex(/^\d{1,5}$/, errorMessages.PHONE_EXTENSION_FORMAT));
defineRule("date-of-loss-required", required(errorMessages.DATE_OF_LOSS_REQUIRED));
defineRule("damage-types-required", required(errorMessages.DAMAGE_TYPES_REQUIRED));
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
defineRule("city-required", required(errorMessages.CITY_REQUIRED));
defineRule("date-of-birth-required", required(errorMessages.DATE_OF_BIRTH_REQUIRED));
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
defineRule("street-address-required", required(errorMessages.STREET_ADDRESS_REQUIRED));
defineRule("loss-time-required", required(errorMessages.LOSS_TIME_REQUIRED));
defineRule("loss-location-required", required(errorMessages.LOSS_LOCATION_REQUIRED));
defineRule("subrogation-required", required(errorMessages.SUBROGATION_REQUIRED));
defineRule("claim-number-required", required(errorMessages.CLAIM_NUMBER_REQUIRED));

export default {
    name: "policy-info",
    mixins: [],
    data() {
        return {
            clientConfig: {},
            policyNumber: this.getPolicyNumberFromStore(),
            policyZip: this.getPolicyZipFromStore(),
            phoneNumber: this.getPhoneNumberFromStore(),
            phoneExtension: this.getPhoneExtensionFromStore(),
            dateOfLoss: this.getDateOfLossFromStore(),
            lastName: this.getLastNameFromStore(),
            streetAddress: this.getStreetAddressFromStore(),
            damageCause: this.getDamageCauseFromStore(),
            policyState: this.getPolicyStateFromStore(),
            city: this.getCityFromStore(),
            dateOfBirth: this.getDateOfBirthFromStore(),
            lossTime: this.getLossTimeFromStore(),
            morePolicyQuestions: this.getMorePolicyQuestionsFromStore(),
            subrogationSelectedValue: this.getSubrogationSelectedValueFromStore(),
            lossLocation: this.getLossLocationFromStore(),
            claimNumber: this.getClaimNumberFromStore(),
        };
    },
    components: {
        Form,
        funnelHeader,
        insuranceNavBar,
        funnelSubHeader,
        textboxQuestion,
        datePickerPopup,
        dropdownQuestion,
        morePolicyQuestions,
        buttonQuestion,
    },
    computed: {
        stateOptions() {
            return stateOptions;
        },
        today() {
            return new Date();
        },
        clientLogoImageSrc() {
            return this.clientConfig?.ClientLogoWidget?.Image || "";
        },
        subHeaderTextOverride() {
            return this.clientConfig?.PageTitleOverrideWidget?.Text || "";
        },
        subHeaderSubTextOverride() {
            return this.clientConfig?.PageInstructionsOverrideWidget?.Text || "";
        },
        policyNumberLabelOverride() {
            return this.clientConfig?.PolicyNumberLabelOverrideWidget?.Text || "";
        },
        policyHelperText() {
            return this.clientConfig?.PolicyHelperTextOverrideWidget?.Text;
        },
        disclaimerText() {
            return this.clientConfig?.DisclaimerWidget?.Text;
        },
        displayDisclaimerText() {
            return this.disclaimerText !== null && this.disclaimerText !== "";
        },
        damageTypesQuestionText() {
            return this.getCmsContent("DamageTypesWidget", "QuestionText");
        },
        damageTypesOptions() {
            const options = {};

            const answers = this.getCmsContent("DamageTypesWidget", "Answers");
            if (!Array.isArray(answers)) {
                return options;
            }
            for (const answer of answers) {
                options[answer.Name] = answer.Text;
            }

            return options;
        },
        lossTimeOptions() {
            const options = {};

            const answers = this.getCmsContent("TimeOfLossWidget", "Answers");
            for (const answer of answers) {
                options[answer.Name] = answer.Text;
            }

            return options;
        },
        timeOfLossQuestionText() {
            return this.getCmsContent("TimeOfLossWidget", "QuestionText");
        },
        lossLocationOptions() {
            const options = {};

            const answers = this.getCmsContent("LossLocationQuestionWidget", "Answers");
            for (const answer of answers) {
                options[answer.Name] = answer.Text;
            }

            return options;
        },
        parsedClientConfig() {
            const raw = this.clientConfig?.ConfigWidget?.Text;
            if (!raw) return {};
            try {
                return JSON.parse(raw);
            } catch (err) {
                console.warn("Failed to parse clientConfig.ConfigWidget.Text", err);
                return {};
            }
        },
        displayLossState() {
            return this.parsedClientConfig.displayLossState ?? false;
        },
        displayLossCity() {
            return this.parsedClientConfig.displayLossCity ?? false;
        },
        displayLossLocation() {
            return this.parsedClientConfig.displayLossLocation ?? false;
        },
        displaySubrogation() {
            return this.parsedClientConfig.displaySubrogation ?? false;
        },
        displayStreetAddress() {
            return this.parsedClientConfig.displayStreetAddress ?? false;
        },
        displayDateOfBirth() {
            return this.parsedClientConfig.displayDateOfBirth ?? false;
        },
        displayLastName() {
            return this.parsedClientConfig.displayLastName ?? false;
        },
        displayLossTime() {
            return this.parsedClientConfig.displayLossTime ?? false;
        },
        displayPolicyHelperText() {
            return this.policyHelperText !== null && this.policyHelperText !== "";
        },
        subrogationQuestionText() {
            return this.getCmsContent("SubrogationQuestionWidget", "QuestionText");
        },
        subrogationAnswers() {
            return this.getCmsContent("SubrogationQuestionWidget", "Answers");
        },
        lossLocationQuestionText() {
            return this.getCmsContent("LossLocationQuestionWidget", "QuestionText");
        },
        morePolicyQuestionsWidgetName() {
            // State Farm may be the only one who uses this
            return this.parsedClientConfig.OverrideMorePolicyQuestions
                ? "MorePolicyQuestionsOverrideWidget"
                : "MorePolicyQuestionsWidget";
        },
        // Only ask for a claim number if the user indicated additional damage
        // occurred or the vehicle was a rental, per the morePolicyQuestions answers.
        displayClaimNumber() {
            const additionalDamageFlag =
                morePolicyQuestionAnswerToFlag[morePolicyQuestionAnswers.ADDITIONAL_DAMAGE];
            const rentalFlag = morePolicyQuestionAnswerToFlag[morePolicyQuestionAnswers.RENTAL];
            const otherResponsibleParty =
                morePolicyQuestionAnswerToFlag[morePolicyQuestionAnswers.OTHER_RESPONSIBLE_PARTY];
            return Boolean(
                this.morePolicyQuestions?.[additionalDamageFlag] ||
                    this.morePolicyQuestions?.[rentalFlag] ||
                    this.morePolicyQuestions?.[otherResponsibleParty]
            );
        },
    },
    // Ensure CMS content is fetched during route navigation without depending on `to`/`from`
    async beforeRouteEnter(to, from, next) {
        const clientConfigPageName = `client_${store.getters.order.payment.parentAccountNumber}`;
        const clientConfigPromise = fetchCmsContentForPage(clientConfigPageName);

        const pageName = to.name;
        const cmsContentPromise = fetchCmsContentForPage(pageName);
        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: cmsContentPromise,
            },
            {
                resultKey: "clientConfig",
                promise: clientConfigPromise,
            },
        ];
        const resultMap = await settleAllPromises(promiseResultMap);
        next((vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            vm.clientConfig = resultMap.clientConfig ?? {};
            policyNumberValidationConfig = parsePolicyNumberValidationWidget(
                vm.clientConfig?.PolicyNumberValidationWidget
            );
            // The load-session API can return damageCause in a different case than
            // the CMS answer values. Reconcile it so the dropdown pre-selects.
            vm.damageCause = vm.matchDamageCauseToOption(vm.damageCause);
            debugLog(
                `policy-infoclientConfig::${clientConfigPageName}`,
                JSON.stringify(vm.clientConfig)
            );
        });
    },

    methods: {
        getPolicyNumberFromStore() {
            return store.getters.order.policy.policyNumber;
        },
        getPolicyZipFromStore() {
            return store.getters.order.customer.address.zipCode;
        },
        getPhoneNumberFromStore() {
            return store.getters.order.customer.phoneNumber;
        },
        getPhoneExtensionFromStore() {
            return store.getters.order.customer.phoneExtension;
        },
        getDateOfLossFromStore() {
            return store.getters.order.damage.dateOfLoss;
        },
        getDamageCauseFromStore() {
            return store.getters.order.damage.damageCause;
        },
        // Maps a stored damageCause to the matching dropdown option value using a
        // case-insensitive comparison (load-session can return it uppercased).
        // Returns the canonical option value, or the original value if no match.
        matchDamageCauseToOption(value) {
            if (!value) {
                return value;
            }
            const optionValues = Object.values(this.damageTypesOptions ?? {});
            const match = optionValues.find(
                (option) => option?.toLowerCase() === value.toLowerCase()
            );
            return match ?? value;
        },
        getPolicyStateFromStore() {
            return store.getters.order.damage.damageState;
        },
        getCityFromStore() {
            return store.getters.order.damage.damageCity;
        },
        getDateOfBirthFromStore() {
            return store.getters.order.policy.dateOfBirth;
        },
        getLastNameFromStore() {
            return store.getters.order.policy.lastName;
        },
        getStreetAddressFromStore() {
            return store.getters.order.policy.streetAddress;
        },
        getLossTimeFromStore() {
            return store.getters.order.policy.lossTime;
        },
        getSubrogationSelectedValueFromStore() {
            return store.getters.order.policy.subrogation;
        },
        getMorePolicyQuestionsFromStore() {
            return store.getters.order.policy.morePolicyQuestions;
        },
        getLossLocationFromStore() {
            return store.getters.order.policy.lossLocation;
        },
        getClaimNumberFromStore() {
            return store.getters.order.payment.insuranceCoverage.claimNumber;
        },
        cancelButtonAction() {
            this.$router.navigateWithoutSaving(
                this.navigationScenarios.CLICKED_CANCEL_VERIFICATION,
                this.pageName
            );
        },
        async forwardButtonAction() {
            // Explicitly (re)validate every field before navigating, rather than relying
            // solely on isForwardActionDisabled/meta.valid already being accurate and on the
            // Continue button's incidental native form-submission side effect to surface
            // error messages. This guarantees the CMS-driven policy number format error (and
            // any other field's error) is actually rendered when Continue is clicked while
            // the form is invalid.
            const isValid = await this.isFormValid(this.$refs.theForm);
            if (!isValid) {
                return;
            }

            this.dispatchStoreAction(
                this.storeActions.SAVE_INSURANCE_DETAILS,
                {
                    policyNumber: this.policyNumber,
                    zipCode: this.policyZip,
                    phoneNumber: this.phoneNumber,
                    phoneExtension: this.phoneExtension,
                    state: null,
                    city: null,
                    morePolicyQuestions: this.morePolicyQuestions,
                    lossLocation: this.lossLocation,
                    lossTime: this.lossTime,
                    lastName: this.lastName,
                    dateOfBirth: this.dateOfBirth,
                    subrogation: this.subrogationSelectedValue,
                    streetAddress: this.streetAddress,
                    claimNumber: this.claimNumber,
                },
                false
            );

            this.dispatchStoreAction(
                this.storeActions.SAVE_DAMAGE_DETAILS,
                {
                    dateOfLoss: this.dateOfLoss,
                    damageCause: this.damageCause,
                    damageState: this.policyState,
                    damageCity: this.city,
                },
                false
            );

            this.$router.navigateWithSaving(
                this.navigationScenarios.CLICKED_FORWARD,
                this.pageName
            );
        },
        arePagePrerequisitesValid() {
            return true;
        },
    },
};
</script>

<style lang="scss">
.cc-page-title {
    font-size: 20px !important;
    line-height: 1.325;
    font-weight: 300;
    color: $black;
}

.cc-page-instructions {
    font-size: 16px !important;
    font-weight: 400;
    color: $gray-600;
    line-height: 1.625;
}

.helper-text {
    font-size: 14px !important;
    font-weight: 400;
    color: $gray-600;
    line-height: 1.625;
    font-style: italic;
}

.disclaimer-text {
    font-size: 12px !important;
    font-weight: 400;
    color: $gray-600;
    line-height: 1.625;
}
</style>
