import { z } from "zod";
import { DEFAULT_MONTHLY_SUPPORT } from "@/lib/constants";
import { isSponsorLoginUsername, sponsorPhoneIdentity } from "@/lib/sponsor-account";
import { normalizePhone } from "@/lib/utils";

const blankToNull = (value: unknown) =>
  typeof value === "string" && value.trim() === "" ? null : value;

function optionalText(max: number, message: string) {
  return z.preprocess(
    blankToNull,
    z.string().trim().max(max, message).nullable().optional()
  ).transform((value) => value ?? null);
}

const requiredPhone = z
  .string()
  .trim()
  .transform((value, context) => {
    const normalized = normalizePhone(value);
    if (!normalized) {
      context.addIssue({ code: "custom", message: "أدخل رقم هاتف صحيحاً بصيغة دولية" });
      return z.NEVER;
    }
    return normalized;
  });

const requiredSponsorPhone = requiredPhone.transform((value, context) => {
    const identity = sponsorPhoneIdentity(value);
    if (!identity) {
      context.addIssue({
        code: "custom",
        message: "أدخل رقم هاتف صحيحًا يبدأ بأحد الرموز +249 أو +966 أو +971 أو +968"
      });
      return z.NEVER;
    }
    return identity.phone;
});

const optionalPhone = z.preprocess(
  blankToNull,
  z.union([
    z
      .string()
      .trim()
      .transform((value, context) => {
        const normalized = normalizePhone(value);
        if (!normalized) {
          context.addIssue({ code: "custom", message: "رقم التواصل غير صحيح" });
          return z.NEVER;
        }
        return normalized;
      }),
    z.null()
  ])
);

const password = z.string().min(6, "يجب ألا تقل كلمة المرور عن 6 أحرف.");

const optionalDate = z.preprocess(
  blankToNull,
  z.union([z.iso.date("التاريخ غير صحيح"), z.null()])
);

const optionalAmount = z.preprocess(
  blankToNull,
  z.union([
    z.coerce.number().int().min(1_000, "المبلغ الشهري غير صحيح"),
    z.null()
  ])
);

const loginIdentifier = z
  .string()
  .trim()
  .min(1, "أدخل البريد الإلكتروني أو رقم الهاتف")
  .transform((value, context) => {
    if (value.includes("@")) {
      const email = z.email().safeParse(value);
      if (!email.success) {
        context.addIssue({ code: "custom", message: "البريد الإلكتروني غير صحيح" });
        return z.NEVER;
      }
      return { type: "email" as const, value: email.data.toLowerCase() };
    }

    const compact = value.replace(/[()\s-]/g, "");
    if (compact.startsWith("0")) {
      if (!isSponsorLoginUsername(compact)) {
        context.addIssue({ code: "custom", message: "اسم مستخدم المتبرع غير صحيح" });
        return z.NEVER;
      }
      return { type: "username" as const, value: compact };
    }

    const phone = normalizePhone(compact);
    if (!phone) {
      context.addIssue({ code: "custom", message: "رقم الهاتف غير صحيح" });
      return z.NEVER;
    }
    return { type: "phone" as const, value: phone };
  });

export const loginSchema = z.object({
  identifier: loginIdentifier,
  password
});

export const orphanSchema = z.object({
  fullName: optionalText(120, "الاسم طويل"),
  dateOfBirth: optionalDate,
  gender: z.preprocess(blankToNull, z.enum(["male", "female"]).nullable()),
  sponsorNotes: optionalText(3_000, "ملاحظات المتبرع طويلة"),
  privateNotes: optionalText(3_000, "ملاحظات الإدارة طويلة"),
  guardianName: optionalText(120, "اسم ولي الأمر طويل"),
  guardianPhone: optionalPhone,
  guardianRelationship: optionalText(80, "صلة ولي الأمر طويلة"),
  address: optionalText(500, "العنوان طويل"),
  bankName: optionalText(120, "اسم البنك طويل"),
  bankAccountName: optionalText(120, "اسم صاحب الحساب طويل"),
  bankAccountNumber: optionalText(120, "رقم الحساب طويل"),
  monthlyNeed: optionalAmount,
  status: z.enum(["available", "partially_covered", "fully_covered", "paused", "archived"]).optional()
});

export const sponsorSchema = z.object({
  fullName: z.string().trim().min(3, "اسم المتبرع مطلوب").max(120, "الاسم طويل"),
  phone: requiredSponsorPhone,
  password,
  isActive: z.boolean().default(true)
});

export const sponsorUpdateSchema = z.object({
  id: z.uuid("حساب المتبرع غير صحيح"),
  fullName: z.string().trim().min(3, "اسم المتبرع مطلوب").max(120, "الاسم طويل"),
  phone: requiredSponsorPhone
});

export const passwordResetSchema = z
  .object({
    id: z.uuid("الحساب غير صحيح"),
    password,
    confirmation: z.string()
  })
  .refine((value) => value.password === value.confirmation, {
    path: ["confirmation"],
    message: "تأكيد كلمة المرور غير مطابق"
  });

export const sponsorshipSchema = z.object({
  donorId: z.uuid("المتبرع غير صحيح"),
  orphanId: z.uuid("الحالة غير صحيحة"),
  monthlyAmount: z.coerce
    .number()
    .int()
    .min(1_000, "المبلغ الشهري غير صحيح")
    .default(DEFAULT_MONTHLY_SUPPORT),
  startDate: z.iso.date("تاريخ البداية غير صحيح"),
  notes: optionalText(2_000, "الملاحظات طويلة")
});

export const sponsorshipUpdateSchema = z.object({
  id: z.uuid("علاقة الكفالة غير صحيحة"),
  monthlyAmount: z.coerce.number().int().min(1_000, "المبلغ الشهري غير صحيح"),
  status: z.enum(["active", "paused", "ended"]),
  endDate: z.union([z.iso.date("تاريخ النهاية غير صحيح"), z.literal("")]).optional(),
  stopReason: optionalText(500, "سبب الإيقاف طويل"),
  notes: optionalText(2_000, "الملاحظات طويلة")
});

export const orphanDocumentTypeSchema = z.enum([
  "orphan_national_id",
  "father_death_certificate",
  "guardian_national_id"
]);

export const sponsorMonthlyPaymentSchema = z.object({
  id: z.uuid("سجل الدفع الشهري غير صحيح"),
  expectedAmount: z.coerce.number().int().min(0, "المبلغ المتوقع غير صحيح"),
  receivedAmount: z.coerce.number().int().min(0, "المبلغ المستلم غير صحيح"),
  paymentDate: optionalDate,
  internalNotes: optionalText(2_000, "الملاحظات طويلة")
}).superRefine((value, context) => {
  if (value.receivedAmount > 0 && !value.paymentDate) {
    context.addIssue({
      code: "custom",
      path: ["paymentDate"],
      message: "تاريخ الدفع مطلوب عند تسجيل مبلغ مستلم"
    });
  }
});

export const orphanTransferSchema = z.object({
  id: z.uuid("سجل التحويل غير صحيح").optional(),
  sponsorId: z.uuid("المتبرع المختار غير صحيح"),
  orphanId: z.uuid("الحالة المختارة غير صحيحة"),
  amount: z.coerce.number().int().min(0, "مبلغ التحويل غير صحيح"),
  transferDate: z.iso.date("تاريخ التحويل غير صحيح"),
  reference: optionalText(120, "مرجع التحويل طويل"),
  sponsorVisibleNotes: optionalText(2_000, "ملاحظات المتبرع طويلة"),
  internalNotes: optionalText(2_000, "الملاحظات الداخلية طويلة")
});
