/**
 * SIM Domain - Schemas
 */

import { z } from "zod";

export const simStatusSchema = z.enum(["active", "suspended", "cancelled", "pending"]);

export const simTypeSchema = z.enum(["standard", "nano", "micro", "esim"]);

export const simDetailsSchema = z.object({
  account: z.string(),
  status: simStatusSchema,
  planCode: z.string(),
  planName: z.string(),
  simType: simTypeSchema,
  iccid: z.string(),
  eid: z.string(),
  msisdn: z.string(),
  imsi: z.string(),
  remainingQuotaMb: z.number(),
  remainingQuotaKb: z.number(),
  voiceMailEnabled: z.boolean(),
  callWaitingEnabled: z.boolean(),
  internationalRoamingEnabled: z.boolean(),
  networkType: z.string(),
  activatedAt: z.string().optional(),
  expiresAt: z.string().optional(),
  startDate: z.string().optional(),
});

export const recentDayUsageSchema = z.object({
  date: z.string(),
  usageKb: z.number(),
  usageMb: z.number(),
});

export const simUsageSchema = z.object({
  account: z.string(),
  todayUsageMb: z.number(),
  todayUsageKb: z.number(),
  monthlyUsageMb: z.number().optional(),
  monthlyUsageKb: z.number().optional(),
  recentDaysUsage: z.array(recentDayUsageSchema),
  isBlacklisted: z.boolean(),
  lastUpdated: z.string().optional(),
});

export const simTopUpHistoryEntrySchema = z.object({
  quotaKb: z.number(),
  quotaMb: z.number(),
  addedDate: z.string(),
  expiryDate: z.string(),
  campaignCode: z.string(),
});

export const simTopUpHistorySchema = z.object({
  account: z.string(),
  totalAdditions: z.number(),
  additionCount: z.number(),
  history: z.array(simTopUpHistoryEntrySchema),
});

/**
 * Combined SIM info payload (details + usage)
 */
export const simInfoSchema = z.object({
  details: simDetailsSchema,
  usage: simUsageSchema,
});

// ============================================================================
// SIM Management Request Schemas
// ============================================================================

export const simTopUpRequestSchema = z.object({
  quotaMb: z
    .number()
    .int()
    .min(100, "Quota must be at least 100MB")
    .max(51200, "Quota must be 50GB or less"),
});

/**
 * Schema for SIM top-up pricing information
 */
export const simTopUpPricingSchema = z.object({
  pricePerGbJpy: z.number().positive("Price per GB must be positive"),
  minQuotaMb: z.number().int().positive("Minimum quota must be positive"),
  maxQuotaMb: z.number().int().positive("Maximum quota must be positive"),
  currency: z.string().default("JPY"),
});

export type SimTopUpPricing = z.infer<typeof simTopUpPricingSchema>;

/**
 * Schema for top-up pricing preview request
 */
export const simTopUpPricingPreviewRequestSchema = z.object({
  quotaMb: z.number().int().positive("Quota must be positive"),
});

export type SimTopUpPricingPreviewRequest = z.infer<typeof simTopUpPricingPreviewRequestSchema>;

/**
 * Schema for top-up pricing preview response
 */
export const simTopUpPricingPreviewResponseSchema = z.object({
  quotaMb: z.number(),
  quotaGb: z.number(),
  totalPriceJpy: z.number(),
  pricePerGbJpy: z.number(),
  currency: z.string(),
});

export type SimTopUpPricingPreviewResponse = z.infer<typeof simTopUpPricingPreviewResponseSchema>;

export const simPlanChangeRequestSchema = z.object({
  newPlanCode: z.string().min(1, "New plan code is required"),
  assignGlobalIp: z.boolean().optional(),
  scheduledAt: z
    .string()
    .regex(/^\d{8}$/, "Scheduled date must be in YYYYMMDD format")
    .optional(),
});

export const simCancelRequestSchema = z.object({
  scheduledAt: z
    .string()
    .regex(/^\d{8}$/, "Scheduled date must be in YYYYMMDD format")
    .optional(),
});

export const simTopUpHistoryRequestSchema = z.object({
  fromDate: z
    .string()
    .regex(/^\d{8}$/, "From date must be in YYYYMMDD format"),
  toDate: z
    .string()
    .regex(/^\d{8}$/, "To date must be in YYYYMMDD format"),
});

export const simFeaturesUpdateRequestSchema = z.object({
  voiceMailEnabled: z.boolean().optional(),
  callWaitingEnabled: z.boolean().optional(),
  internationalRoamingEnabled: z.boolean().optional(),
  networkType: z.enum(["4G", "5G"]).optional(),
});

export const simReissueRequestSchema = z.object({
  newEid: z
    .string()
    .regex(/^\d{32}$/, "EID must be exactly 32 digits")
    .optional(),
  simType: z.enum(["physical", "esim"]).optional(),
});

// Enhanced cancellation request with more details
export const simCancelFullRequestSchema = z.object({
  cancellationMonth: z.string().regex(/^\d{4}-\d{2}$/, "Cancellation month must be in YYYY-MM format"),
  confirmRead: z.boolean(),
  confirmCancel: z.boolean(),
  alternativeEmail: z.string().email().optional().or(z.literal("")),
  comments: z.string().max(1000).optional(),
}).refine(
  (data) => data.confirmRead === true && data.confirmCancel === true,
  { message: "You must confirm both checkboxes to proceed" }
);

// Top-up request with enhanced details for email
export const simTopUpFullRequestSchema = z.object({
  quotaMb: z
    .number()
    .int()
    .min(100, "Quota must be at least 100MB")
    .max(51200, "Quota must be 50GB or less"),
});

// Change plan request with Salesforce product info
export const simChangePlanFullRequestSchema = z.object({
  newPlanCode: z.string().min(1, "New plan code is required"),
  newPlanSku: z.string().min(1, "New plan SKU is required"),
  newPlanName: z.string().optional(),
  assignGlobalIp: z.boolean().optional(),
});

const simMnpFormSchema = z.object({
  reservationNumber: z.string().min(1, "Reservation number is required"),
  expiryDate: z.string().regex(/^\d{8}$/, "Expiry date must be in YYYYMMDD format"),
  phoneNumber: z.string().min(1, "Phone number is required"),
  mvnoAccountNumber: z.string().optional(),
  portingLastName: z.string().optional(),
  portingFirstName: z.string().optional(),
  portingLastNameKatakana: z.string().optional(),
  portingFirstNameKatakana: z.string().optional(),
  portingGender: z.string().optional(),
  portingDateOfBirth: z
    .string()
    .regex(/^\d{8}$/, "Birthday must be in YYYYMMDD format")
    .optional(),
});

export const simCardTypeSchema = z.enum(["eSIM", "Physical SIM"]);

export const simActivationTypeSchema = z.enum(["Immediate", "Scheduled"]);

export const simConfigureFormSchema = z
  .object({
    simType: simCardTypeSchema,
    eid: z
      .string()
      .min(15, "EID must be at least 15 characters")
      .max(32, "EID must be at most 32 characters")
      .optional(),
    selectedAddons: z.array(z.string()).default([]),
    activationType: simActivationTypeSchema,
    scheduledActivationDate: z
      .string()
      .regex(/^\d{8}$/, "Scheduled date must be in YYYYMMDD format")
      .optional(),
    wantsMnp: z.boolean().default(false),
    mnpData: simMnpFormSchema.optional(),
  })
  .superRefine((data, ctx) => {
    if (data.simType === "eSIM" && (!data.eid || data.eid.trim().length < 15)) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        path: ["eid"],
        message: "EID is required for eSIM configuration",
      });
    }

    if (data.activationType === "Scheduled" && !data.scheduledActivationDate) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        path: ["scheduledActivationDate"],
        message: "Scheduled activation date is required when activation type is Scheduled",
      });
    }

    if (data.wantsMnp) {
      if (!data.mnpData) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          path: ["mnpData"],
          message: "MNP data is required when porting is selected",
        });
        return;
      }

      const { reservationNumber, expiryDate, phoneNumber } = data.mnpData;
      if (!reservationNumber) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          path: ["mnpData", "reservationNumber"],
          message: "Reservation number is required",
        });
      }
      if (!expiryDate) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          path: ["mnpData", "expiryDate"],
          message: "Reservation expiry date is required",
        });
      }
      if (!phoneNumber) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          path: ["mnpData", "phoneNumber"],
          message: "Phone number is required for porting",
        });
      }
    }
  });

// ============================================================================
// SIM Order Activation Schemas
// ============================================================================

export const simOrderActivationMnpSchema = z.object({
  reserveNumber: z.string().min(1, "Reserve number is required"),
  reserveExpireDate: z.string().regex(/^\d{8}$/, "Reserve expire date must be in YYYYMMDD format"),
  account: z.string().optional(),
  firstnameKanji: z.string().optional(),
  lastnameKanji: z.string().optional(),
  firstnameZenKana: z.string().optional(),
  lastnameZenKana: z.string().optional(),
  gender: z.string().optional(),
  birthday: z.string().regex(/^\d{8}$/, "Birthday must be in YYYYMMDD format").optional(),
});

export const simOrderActivationAddonsSchema = z.object({
  voiceMail: z.boolean().optional(),
  callWaiting: z.boolean().optional(),
});

export const simOrderActivationRequestSchema = z.object({
  planSku: z.string().min(1, "Plan SKU is required"),
  simType: simCardTypeSchema,
  eid: z.string().min(15, "EID must be at least 15 characters").optional(),
  activationType: simActivationTypeSchema,
  scheduledAt: z.string().regex(/^\d{8}$/, "Scheduled date must be in YYYYMMDD format").optional(),
  addons: simOrderActivationAddonsSchema.optional(),
  mnp: simOrderActivationMnpSchema.optional(),
  msisdn: z.string().min(1, "Phone number (msisdn) is required"),
  oneTimeAmountJpy: z.number().nonnegative("One-time amount must be non-negative"),
  monthlyAmountJpy: z.number().nonnegative("Monthly amount must be non-negative"),
}).refine(
  (data) => {
    // If simType is eSIM, eid is required
    if (data.simType === "eSIM" && (!data.eid || data.eid.length < 15)) {
      return false;
    }
    return true;
  },
  {
    message: "EID is required for eSIM and must be at least 15 characters",
    path: ["eid"],
  }
).refine(
  (data) => {
    // If activationType is Scheduled, scheduledAt is required
    if (data.activationType === "Scheduled" && !data.scheduledAt) {
      return false;
    }
    return true;
  },
  {
    message: "Scheduled date is required for Scheduled activation",
    path: ["scheduledAt"],
  }
);

export type SimOrderActivationRequest = z.infer<typeof simOrderActivationRequestSchema>;
export type SimOrderActivationMnp = z.infer<typeof simOrderActivationMnpSchema>;
export type SimOrderActivationAddons = z.infer<typeof simOrderActivationAddonsSchema>;

// Legacy aliases for backward compatibility
export const simTopupRequestSchema = simTopUpRequestSchema;
export type SimTopupRequest = SimTopUpRequest;

export const simChangePlanRequestSchema = simPlanChangeRequestSchema;
export type SimChangePlanRequest = SimPlanChangeRequest;

export const simFeaturesRequestSchema = simFeaturesUpdateRequestSchema;
export type SimFeaturesRequest = SimFeaturesUpdateRequest;

// ============================================================================
// Inferred Types from Schemas (Schema-First Approach)
// ============================================================================

export type SimStatus = z.infer<typeof simStatusSchema>;
export type SimType = z.infer<typeof simTypeSchema>;
export type SimDetails = z.infer<typeof simDetailsSchema>;
export type RecentDayUsage = z.infer<typeof recentDayUsageSchema>;
export type SimUsage = z.infer<typeof simUsageSchema>;
export type SimTopUpHistoryEntry = z.infer<typeof simTopUpHistoryEntrySchema>;
export type SimTopUpHistory = z.infer<typeof simTopUpHistorySchema>;
export type SimInfo = z.infer<typeof simInfoSchema>;

// Request types (derived from request schemas)
export type SimTopUpRequest = z.infer<typeof simTopUpRequestSchema>;
export type SimPlanChangeRequest = z.infer<typeof simPlanChangeRequestSchema>;
export type SimCancelRequest = z.infer<typeof simCancelRequestSchema>;
export type SimTopUpHistoryRequest = z.infer<typeof simTopUpHistoryRequestSchema>;
export type SimFeaturesUpdateRequest = z.infer<typeof simFeaturesUpdateRequestSchema>;
export type SimReissueRequest = z.infer<typeof simReissueRequestSchema>;
export type SimCancelFullRequest = z.infer<typeof simCancelFullRequestSchema>;
export type SimTopUpFullRequest = z.infer<typeof simTopUpFullRequestSchema>;
export type SimChangePlanFullRequest = z.infer<typeof simChangePlanFullRequestSchema>;
export type SimConfigureFormData = z.infer<typeof simConfigureFormSchema>;
export type SimCardType = z.infer<typeof simCardTypeSchema>;
export type ActivationType = z.infer<typeof simActivationTypeSchema>;
export type MnpData = z.infer<typeof simMnpFormSchema>;

export interface SimConfigureFormToRequestOptions {
  planSku: string;
  msisdn: string;
  monthlyAmountJpy: number;
  oneTimeAmountJpy: number;
  addons?: SimOrderActivationAddons;
}

export function simConfigureFormToRequest(
  formData: SimConfigureFormData,
  options: SimConfigureFormToRequestOptions
): SimOrderActivationRequest {
  const scheduledAt =
    formData.activationType === "Scheduled" ? formData.scheduledActivationDate : undefined;

  const mnp =
    formData.wantsMnp && formData.mnpData
      ? {
          reserveNumber: formData.mnpData.reservationNumber,
          reserveExpireDate: formData.mnpData.expiryDate,
          account: formData.mnpData.mvnoAccountNumber ?? undefined,
          firstnameKanji: formData.mnpData.portingFirstName ?? undefined,
          lastnameKanji: formData.mnpData.portingLastName ?? undefined,
          firstnameZenKana: formData.mnpData.portingFirstNameKatakana ?? undefined,
          lastnameZenKana: formData.mnpData.portingLastNameKatakana ?? undefined,
          gender: formData.mnpData.portingGender ?? undefined,
          birthday: formData.mnpData.portingDateOfBirth ?? undefined,
        }
      : undefined;

  return simOrderActivationRequestSchema.parse({
    planSku: options.planSku,
    simType: formData.simType,
    eid: formData.simType === "eSIM" ? formData.eid?.trim() || undefined : undefined,
    activationType: formData.activationType,
    scheduledAt,
    addons: options.addons,
    mnp,
    msisdn: options.msisdn,
    oneTimeAmountJpy: options.oneTimeAmountJpy,
    monthlyAmountJpy: options.monthlyAmountJpy,
  });
}
