'use server';

import { z } from 'zod';
import { getDbClient } from '../dbClient';
import { UserSettings } from '../db-types';
import { withUser } from '@/app/lib/auth';
import { AuthenticatedUser } from '../types/next-auth';
import { unstable_noStore as noStore } from 'next/cache';
import { IntlTemplateFn } from '@/app/i18n';
import { getTranslations, getLocale } from "next-intl/server";
import { revalidatePath } from 'next/cache';
import { gotoHomeWithMessage } from './navigationActions';
import * as IBAN from 'iban';

export type State = {
    errors?: {
        ownerName?: string[];
        ownerStreet?: string[];
        ownerTown?: string[];
        ownerIBAN?: string[];
        currency?: string[];
        show2dCodeInMonthlyStatement?: string[];
    };
    message?: string | null;
    success?: boolean;
};

/**
 * Schema for validating user settings form fields
 */
const FormSchema = (t: IntlTemplateFn) => z.object({
    ownerName: z.string().max(25).optional(),
    ownerStreet: z.string().max(25).optional(),
    ownerTown: z.string().max(27).optional(),
    ownerIBAN: z.string()
        .optional()
        .refine(
            (val) => {
                if (!val || val.trim() === '') return true;
                // Remove spaces and validate using iban.js library
                const cleaned = val.replace(/\s/g, '').toUpperCase();
                return IBAN.isValid(cleaned);
            },
            { message: t("owner-iban-invalid") }
        ),
    currency: z.string().optional(),
    show2dCodeInMonthlyStatement: z.boolean().optional().nullable(),
})
.refine((data) => {
    if (data.show2dCodeInMonthlyStatement) {
        return !!data.ownerName && data.ownerName.trim().length > 0;
    }
    return true;
}, {
    message: t("owner-name-required"),
    path: ["ownerName"],
})
.refine((data) => {
    if (data.show2dCodeInMonthlyStatement) {
        return !!data.ownerStreet && data.ownerStreet.trim().length > 0;
    }
    return true;
}, {
    message: t("owner-street-required"),
    path: ["ownerStreet"],
})
.refine((data) => {
    if (data.show2dCodeInMonthlyStatement) {
        return !!data.ownerTown && data.ownerTown.trim().length > 0;
    }
    return true;
}, {
    message: t("owner-town-required"),
    path: ["ownerTown"],
})
.refine((data) => {
    if (data.show2dCodeInMonthlyStatement) {
        if (!data.ownerIBAN || data.ownerIBAN.trim().length === 0) {
            return false;
        }
        // Validate IBAN format when required
        const cleaned = data.ownerIBAN.replace(/\s/g, '').toUpperCase();
        return IBAN.isValid(cleaned);
    }
    return true;
}, {
    message: t("owner-iban-required"),
    path: ["ownerIBAN"],
})
.refine((data) => {
    if (data.show2dCodeInMonthlyStatement) {
        return !!data.currency && data.currency.trim().length > 0;
    }
    return true;
}, {
    message: t("currency-required"),
    path: ["currency"],
});

/**
 * Get user settings
 */
export const getUserSettings = withUser(async (user: AuthenticatedUser) => {
    noStore();

    const dbClient = await getDbClient();
    const { id: userId } = user;

    const userSettings = await dbClient.collection<UserSettings>("userSettings")
        .findOne({ userId });

    return userSettings;
});

/**
 * Get user settings by userId (without authentication)
 * Used for public/shared pages where we need to display owner's payment information
 */
export const getUserSettingsByUserId = async (userId: string): Promise<UserSettings | null> => {
    noStore();

    const dbClient = await getDbClient();

    const userSettings = await dbClient.collection<UserSettings>("userSettings")
        .findOne({ userId });

    return userSettings;
};

/**
 * Update user settings
 */
export const updateUserSettings = withUser(async (user: AuthenticatedUser, prevState: State, formData: FormData) => {
    noStore();

    const t = await getTranslations("user-settings-form.validation");

    const validatedFields = FormSchema(t).safeParse({
        ownerName: formData.get('ownerName') || undefined,
        ownerStreet: formData.get('ownerStreet') || undefined,
        ownerTown: formData.get('ownerTown') || undefined,
        ownerIBAN: formData.get('ownerIBAN') || undefined,
        currency: formData.get('currency') || undefined,
        show2dCodeInMonthlyStatement: formData.get('generateTenantCode') === 'on',
    });

    // If form validation fails, return errors early. Otherwise, continue...
    if (!validatedFields.success) {
        return {
            errors: validatedFields.error.flatten().fieldErrors,
            message: t("validation-failed"),
            success: false,
        };
    }

    const { ownerName, ownerStreet, ownerTown, ownerIBAN, currency, show2dCodeInMonthlyStatement } = validatedFields.data;

    // Normalize IBAN: remove spaces and convert to uppercase
    const normalizedOwnerIBAN = ownerIBAN ? ownerIBAN.replace(/\s/g, '').toUpperCase() : null;

    // Update the user settings in MongoDB
    const dbClient = await getDbClient();
    const { id: userId } = user;

    const userSettings: UserSettings = {
        userId,
        ownerName: ownerName || null,
        ownerStreet: ownerStreet || null,
        ownerTown: ownerTown || null,
        ownerIBAN: normalizedOwnerIBAN,
        currency: currency || null,
        show2dCodeInMonthlyStatement: show2dCodeInMonthlyStatement ?? false,
    };

    await dbClient.collection<UserSettings>("userSettings")
        .updateOne(
            { userId },
            { $set: userSettings },
            { upsert: true }
        );

    revalidatePath('/settings');

    // Get current locale and redirect to home with success message
    const locale = await getLocale();
    await gotoHomeWithMessage(locale, 'userSettingsSaved');

    // This return is needed for TypeScript, but won't be reached due to redirect
    return {
        message: null,
        errors: {},
        success: true,
    };
});
