/**
 * Customer Domain - Schemas
 * 
 * Zod validation schemas for customer domain types.
 * Pattern matches billing and subscriptions domains.
 * 
 * Architecture:
 * - UserAuth: Auth state from portal database (Prisma)
 * - WhmcsClient: Full WHMCS data (raw field names, internal to providers)
 * - User: API response type (normalized camelCase)
 */

import { z } from "zod";

import { countryCodeSchema } from "../common/schema";
import { whmcsClientSchema as whmcsRawClientSchema, whmcsCustomFieldSchema } from "./providers/whmcs/raw.types";

// ============================================================================
// Helper Schemas
// ============================================================================

const stringOrNull = z.union([z.string(), z.null()]);
const booleanLike = z.union([z.boolean(), z.number(), z.string()]);
const numberLike = z.union([z.number(), z.string()]);

/**
 * Normalize boolean-like values to actual booleans
 */
const normalizeBoolean = (value: unknown): boolean | null | undefined => {
  if (value === undefined) return undefined;
  if (value === null) return null;
  if (typeof value === "boolean") return value;
  if (typeof value === "number") return value === 1;
  if (typeof value === "string") {
    const normalized = value.trim().toLowerCase();
    return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
  }
  return null;
};

// ============================================================================
// Address Schemas
// ============================================================================

/**
 * Address schema - matches pattern from other domains (not "CustomerAddress")
 */
export const addressSchema = z.object({
  address1: stringOrNull.optional(),
  address2: stringOrNull.optional(),
  city: stringOrNull.optional(),
  state: stringOrNull.optional(),
  postcode: stringOrNull.optional(),
  country: stringOrNull.optional(),
  countryCode: stringOrNull.optional(),
  phoneNumber: stringOrNull.optional(),
  phoneCountryCode: stringOrNull.optional(),
});

export const addressFormSchema = z.object({
  address1: z.string().min(1, "Address line 1 is required").max(200, "Address line 1 is too long").trim(),
  address2: z.string().max(200, "Address line 2 is too long").trim().optional(),
  city: z.string().min(1, "City is required").max(100, "City name is too long").trim(),
  state: z.string().min(1, "State/Prefecture is required").max(100, "State/Prefecture name is too long").trim(),
  postcode: z.string().min(1, "Postcode is required").max(20, "Postcode is too long").trim(),
  country: z.string().min(1, "Country is required").max(100, "Country name is too long").trim(),
  countryCode: countryCodeSchema.optional(),
  phoneNumber: z.string().optional(),
  phoneCountryCode: z.string().optional(),
});

// ============================================================================
// Profile Edit Schemas
// ============================================================================

/**
 * Profile edit form schema for frontend forms
 * Contains basic editable user profile fields (WHMCS field names)
 */
export const profileEditFormSchema = z.object({
  firstname: z.string().min(1, "First name is required").max(100).trim(),
  lastname: z.string().min(1, "Last name is required").max(100).trim(),
  phonenumber: z.string().optional(),
});

/**
 * Profile display data - includes email for display (read-only)
 * Used for displaying profile information
 */
export const profileDisplayDataSchema = profileEditFormSchema.extend({
  email: z.string().email(),
});

// ============================================================================
// UserAuth Schema (Portal Database - Auth State Only)
// ============================================================================

/**
 * UserAuth - Authentication state from portal database
 * 
 * Source: Portal database (Prisma)
 * Provider: customer/providers/portal/
 * 
 * Contains ONLY auth-related fields:
 * - User ID, email, role
 * - Email verification status
 * - MFA enabled status
 * - Last login timestamp
 */
export const userAuthSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  role: z.enum(["USER", "ADMIN"]),
  emailVerified: z.boolean(),
  mfaEnabled: z.boolean(),
  lastLoginAt: z.string().optional(),
  createdAt: z.string(),
  updatedAt: z.string(),
});

// ============================================================================
// WHMCS-Specific Schemas (Internal to Providers)
// ============================================================================

/**
 * Email preferences from WHMCS
 * Internal to Providers.Whmcs namespace
 */
const emailPreferencesSchema = z.object({
  general: booleanLike.optional(),
  invoice: booleanLike.optional(),
  support: booleanLike.optional(),
  product: booleanLike.optional(),
  domain: booleanLike.optional(),
  affiliate: booleanLike.optional(),
}).transform(prefs => ({
  general: normalizeBoolean(prefs.general),
  invoice: normalizeBoolean(prefs.invoice),
  support: normalizeBoolean(prefs.support),
  product: normalizeBoolean(prefs.product),
  domain: normalizeBoolean(prefs.domain),
  affiliate: normalizeBoolean(prefs.affiliate),
}));

/**
 * Sub-user from WHMCS
 * Internal to Providers.Whmcs namespace
 */
const subUserSchema = z.object({
  id: numberLike,
  name: z.string(),
  email: z.string(),
  is_owner: booleanLike.optional(),
}).transform(user => ({
  id: Number(user.id),
  name: user.name,
  email: user.email,
  is_owner: normalizeBoolean(user.is_owner),
}));

/**
 * Billing stats from WHMCS
 * Internal to Providers.Whmcs namespace
 */
const statsSchema = z.record(
  z.string(), 
  z.union([z.string(), z.number(), z.boolean()])
).optional();

const whmcsRawCustomFieldsArraySchema = z.array(whmcsCustomFieldSchema);

const whmcsCustomFieldsSchema = z
  .union([
    z.record(z.string(), z.string()),
    whmcsRawCustomFieldsArraySchema,
    z
      .object({
        customfield: z
          .union([whmcsCustomFieldSchema, whmcsRawCustomFieldsArraySchema])
          .optional(),
      })
      .passthrough(),
  ])
  .optional();

const whmcsUsersSchema = z
  .union([
    z.array(subUserSchema),
    z
      .object({
        user: z.union([subUserSchema, z.array(subUserSchema)]).optional(),
      })
      .passthrough(),
  ])
  .optional();

/**
 * WhmcsClient - Full WHMCS client data
 * 
 * Raw WHMCS structure with field names as they come from the API.
 * Internal to Providers.Whmcs namespace - not exported at top level.
 * 
 * Includes:
 * - Profile data (firstname, lastname, companyname, etc.)
 * - Billing info (currency_code, defaultgateway, status)
 * - Preferences (email_preferences, allowSingleSignOn)
 * - Relations (users, stats, customfields)
 */
const nullableProfileFields = [
  "firstname",
  "lastname",
  "fullname",
  "companyname",
  "phonenumber",
  "phonenumberformatted",
  "telephoneNumber",
  "status",
  "language",
  "defaultgateway",
  "currency_code",
  "tax_id",
  "notes",
  "datecreated",
  "lastlogin",
] as const;

type NullableProfileKey = (typeof nullableProfileFields)[number];

const nullableProfileOverrides = nullableProfileFields.reduce<Record<string, z.ZodTypeAny>>(
  (acc, field) => {
    acc[field] = z.string().nullable().optional();
    return acc;
  },
  {}
);

export const whmcsClientSchema = whmcsRawClientSchema
  .extend({
    ...nullableProfileOverrides,
    // Allow nullable numeric strings
    defaultpaymethodid: numberLike.nullable().optional(),
    currency: numberLike.nullable().optional(),
    allowSingleSignOn: booleanLike.nullable().optional(),
    email_verified: booleanLike.nullable().optional(),
    marketing_emails_opt_in: booleanLike.nullable().optional(),
    address: addressSchema.nullable().optional(),
    email_preferences: emailPreferencesSchema.nullable().optional(),
    customfields: whmcsCustomFieldsSchema,
    users: whmcsUsersSchema,
    stats: statsSchema.optional(),
  })
  .transform(raw => {
    const coerceNumber = (value: unknown) =>
      value === null || value === undefined ? null : Number(value);

    const coerceOptionalNumber = (value: unknown) =>
      value === null || value === undefined ? undefined : Number(value);

    return {
      ...raw,
      id: Number(raw.id),
      client_id: coerceOptionalNumber((raw as Record<string, unknown>).client_id),
      owner_user_id: coerceOptionalNumber((raw as Record<string, unknown>).owner_user_id),
      userid: coerceOptionalNumber((raw as Record<string, unknown>).userid),
      allowSingleSignOn: normalizeBoolean(raw.allowSingleSignOn),
      email_verified: normalizeBoolean(raw.email_verified),
      marketing_emails_opt_in: normalizeBoolean(raw.marketing_emails_opt_in),
      defaultpaymethodid: coerceNumber(raw.defaultpaymethodid),
      currency: coerceNumber(raw.currency),
    };
  });

// ============================================================================
// User Schema (API Response - Normalized camelCase)
// ============================================================================

/**
 * User - Complete user profile for API responses
 * 
 * Composition: UserAuth (portal DB) + WhmcsClient (WHMCS)
 * Field names match WHMCS API exactly (no transformation)
 * 
 * Use combineToUser() helper to construct from sources
 */
export const userSchema = userAuthSchema.extend({
  // Profile fields (WHMCS field names - direct from API)
  firstname: z.string().nullable().optional(),
  lastname: z.string().nullable().optional(),
  fullname: z.string().nullable().optional(),
  companyname: z.string().nullable().optional(),
  phonenumber: z.string().nullable().optional(),
  language: z.string().nullable().optional(),
  currency_code: z.string().nullable().optional(), // WHMCS uses snake_case for this
  address: addressSchema.optional(),
});

// ============================================================================
// Helper Functions
// ============================================================================

/**
 * Convert address form data to address request format
 * Trims strings and converts empty strings to null
 */
export function addressFormToRequest(form: AddressFormData): Address {
  const emptyToNull = (value?: string | null) => {
    if (value === undefined) return undefined;
    const trimmed = value?.trim();
    return trimmed ? trimmed : null;
  };

  return addressSchema.parse({
    address1: emptyToNull(form.address1),
    address2: emptyToNull(form.address2 ?? null),
    city: emptyToNull(form.city),
    state: emptyToNull(form.state),
    postcode: emptyToNull(form.postcode),
    country: emptyToNull(form.country),
    countryCode: emptyToNull(form.countryCode ?? null),
    phoneNumber: emptyToNull(form.phoneNumber ?? null),
    phoneCountryCode: emptyToNull(form.phoneCountryCode ?? null),
  });
}

/**
 * Convert profile form data to update request format
 * No transformation needed - form already uses WHMCS field names
 */
export function profileFormToRequest(form: ProfileEditFormData): {
  firstname: string;
  lastname: string;
  phonenumber?: string;
} {
  return {
    firstname: form.firstname.trim(),
    lastname: form.lastname.trim(),
    phonenumber: form.phonenumber?.trim() || undefined,
  };
}

/**
 * Combine UserAuth and WhmcsClient into User
 * 
 * This is the single source of truth for constructing User from its sources.
 * No field name transformation - User schema uses WHMCS field names directly.
 * 
 * @param userAuth - Authentication state from portal database
 * @param whmcsClient - Full client data from WHMCS
 * @returns User object for API responses with WHMCS field names
 */
export function combineToUser(userAuth: UserAuth, whmcsClient: WhmcsClient): User {
  return userSchema.parse({
    // Auth state from portal DB
    id: userAuth.id,
    email: userAuth.email,
    role: userAuth.role,
    emailVerified: userAuth.emailVerified,
    mfaEnabled: userAuth.mfaEnabled,
    lastLoginAt: userAuth.lastLoginAt,
    createdAt: userAuth.createdAt,
    updatedAt: userAuth.updatedAt,
    
    // Profile from WHMCS (no transformation - keep field names as-is)
    firstname: whmcsClient.firstname || null,
    lastname: whmcsClient.lastname || null,
    fullname: whmcsClient.fullname || null,
    companyname: whmcsClient.companyname || null,
    phonenumber: whmcsClient.phonenumberformatted || whmcsClient.phonenumber || whmcsClient.telephoneNumber || null,
    language: whmcsClient.language || null,
    currency_code: whmcsClient.currency_code || null,
    address: whmcsClient.address || undefined,
  });
}

// ============================================================================
// Exported Types (Public API)
// ============================================================================

export type User = z.infer<typeof userSchema>;
export type UserAuth = z.infer<typeof userAuthSchema>;
export type UserRole = "USER" | "ADMIN";
export type Address = z.infer<typeof addressSchema>;
export type AddressFormData = z.infer<typeof addressFormSchema>;
export type ProfileEditFormData = z.infer<typeof profileEditFormSchema>;
export type ProfileDisplayData = z.infer<typeof profileDisplayDataSchema>;

// Convenience aliases
export type UserProfile = User; // Alias for user profile
export type AuthenticatedUser = User; // Alias for authenticated user context

// ============================================================================
// Internal Types (For Providers)
// ============================================================================

export type WhmcsClient = z.infer<typeof whmcsClientSchema>;
export type EmailPreferences = z.infer<typeof emailPreferencesSchema>;
export type SubUser = z.infer<typeof subUserSchema>;
export type Stats = z.infer<typeof statsSchema>;

// Export schemas for provider use
export { emailPreferencesSchema, subUserSchema, statsSchema };
