import mongoose, { Schema, Document, Model } from "mongoose";
import type { FunnelDefinition } from "@/lib/funnel/types";

// Extend FunnelDefinition with MongoDB specific fields
export interface IFunnel extends Document {
  // Основные данные воронки
  funnelData: FunnelDefinition;

  // Метаданные для админки
  name: string; // Человеко-читаемое имя для каталога
  description?: string;
  status: "draft" | "published" | "archived";

  // Система версий и истории
  version: number;
  parentFunnelId?: string; // Для создания копий

  // Timestamps
  createdAt: Date;
  updatedAt: Date;
  publishedAt?: Date;

  // Пользовательские данные
  createdBy?: string; // User ID in future
  lastModifiedBy?: string;

  // Статистика использования
  usage: {
    totalViews: number;
    totalCompletions: number;
    lastUsed?: Date;
  };
}

// Вложенные схемы для валидации структуры данных воронки
const TypographyVariantSchema = new Schema(
  {
    text: {
      type: String,
      // НЕ required — позволяет { show: false } без текста, но если указан — не пустой
      validate: {
        validator: function (v: string | undefined): boolean {
          if (v === undefined || v === null) return true;
          return v.trim().length > 0;
        },
        message: "Text field cannot be empty if provided",
      },
    },
    show: { type: Boolean, default: true }, // поддержка флага видимости
    font: {
      type: String,
      enum: ["manrope", "inter", "geistSans", "geistMono"],
      default: "manrope",
    },
    weight: {
      type: String,
      enum: ["regular", "medium", "semiBold", "bold", "extraBold", "black"],
      default: "regular",
    },
    size: {
      type: String,
      enum: ["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl"],
      default: "md",
    },
    align: {
      type: String,
      enum: ["center", "left", "right"],
      default: "center",
    },
    color: {
      type: String,
      enum: [
        "default",
        "primary",
        "secondary",
        "destructive",
        "success",
        "card",
        "accent",
        "muted",
      ],
      default: "default",
    },
    className: String,
  },
  { _id: false }
);

const HeaderDefinitionSchema = new Schema(
  {
    progress: {
      current: Number,
      total: Number,
      value: Number,
      label: String,
      className: String,
    },
    showBackButton: { type: Boolean, default: true },
    showProgress: { type: Boolean, default: true },
    show: { type: Boolean, default: true },
  },
  { _id: false }
);

const ListOptionDefinitionSchema = new Schema(
  {
    id: { type: String, required: true },
    label: { type: String, required: true },
    description: String,
    emoji: String,
    value: String,
    disabled: { type: Boolean, default: false },
  },
  { _id: false }
);

const NavigationConditionSchema = new Schema(
  {
    screenId: { type: String, required: true },
    conditionType: {
      type: String,
      enum: ["options", "values", "unleash"],
      default: "options",
    },
    operator: {
      type: String,
      enum: ["includesAny", "includesAll", "includesExactly", "equals"],
      default: "includesAny",
    },
    optionIds: [{ type: String }],
    values: [{ type: String }],
    // Unleash AB testing fields
    unleashFlag: { type: String },
    unleashVariants: [{ type: String }],
  },
  { _id: false }
);

const NavigationRuleSchema = new Schema(
  {
    conditions: [NavigationConditionSchema],
    nextScreenId: { type: String, required: true },
  },
  { _id: false }
);

const NavigationDefinitionSchema = new Schema(
  {
    rules: [NavigationRuleSchema],
    defaultNextScreenId: String,
    isEndScreen: { type: Boolean, default: false },
    onBackScreenId: String,
  },
  { _id: false }
);

const BottomActionButtonSchema = new Schema(
  {
    show: { type: Boolean, default: true },
    text: String,
    cornerRadius: {
      type: String,
      enum: ["3xl", "full"],
      default: "3xl",
    },
    showPrivacyTermsConsent: { type: Boolean, default: false },
  },
  { _id: false }
);

// Схемы для различных типов экранов (используем Mixed для гибкости)
const ScreenDefinitionSchema = new Schema(
  {
    id: { type: String, required: true },
    template: {
      type: String,
      enum: [
        "info",
        "date",
        "coupon",
        "form",
        "list",
        "email",
        "loaders",
        "soulmate",
        "trialPayment",
        "specialOffer",
        "trialChoice",
      ],
      required: true,
    },
    header: HeaderDefinitionSchema,
    title: { type: TypographyVariantSchema, required: true },
    subtitle: TypographyVariantSchema,
    bottomActionButton: BottomActionButtonSchema,
    navigation: NavigationDefinitionSchema,

    // Специфичные для template поля (используем Mixed для максимальной гибкости)
    description: TypographyVariantSchema, // info, soulmate
    icon: Schema.Types.Mixed, // info
    variables: [Schema.Types.Mixed], // info - динамические переменные для подстановки в текст
    dateInput: Schema.Types.Mixed, // date
    infoMessage: Schema.Types.Mixed, // date
    coupon: Schema.Types.Mixed, // coupon
    copiedMessage: String, // coupon
    fields: [Schema.Types.Mixed], // form
    validationMessages: Schema.Types.Mixed, // form
    list: {
      // list
      selectionType: {
        type: String,
        enum: ["single", "multi"],
      },
      options: [ListOptionDefinitionSchema],
    },
    emailInput: Schema.Types.Mixed, // email
    image: Schema.Types.Mixed, // email, soulmate
    // loaders
    progressbars: Schema.Types.Mixed, // preferred key used by runtime/templates
    variants: [Schema.Types.Mixed], // variants для всех типов
  },
  { _id: false, strict: false }
);

const FunnelMetaSchema = new Schema(
  {
    id: { type: String, required: true },
    version: String,
    title: String,
    description: String,
    firstScreenId: String,
    googleAnalyticsId: String,
    yandexMetrikaId: String,
  },
  { _id: false }
);

const DefaultTextsSchema = new Schema(
  {
    nextButton: { type: String, default: "Next" },
    privacyBanner: { type: String },
  },
  { _id: false }
);

const FunnelDataSchema = new Schema(
  {
    meta: { type: FunnelMetaSchema, required: true },
    defaultTexts: DefaultTextsSchema,
    screens: [ScreenDefinitionSchema],
  },
  { _id: false }
);

const FunnelSchema = new Schema<IFunnel>(
  {
    // Основные данные воронки
    funnelData: {
      type: FunnelDataSchema,
      required: true,
      validate: {
        validator: function (v: FunnelDefinition): boolean {
          // Базовая валидация структуры
          return Boolean(v?.meta && v.meta.id && Array.isArray(v.screens));
        },
        message: "Invalid funnel data structure",
      },
    },

    // Метаданные для админки
    name: {
      type: String,
      required: true,
      trim: true,
      maxlength: 200,
    },
    description: {
      type: String,
      trim: true,
      maxlength: 1000,
    },
    status: {
      type: String,
      enum: ["draft", "published", "archived"],
      default: "draft",
      required: true,
    },

    // Система версий
    version: {
      type: Number,
      default: 1,
      min: 1,
    },
    parentFunnelId: {
      type: Schema.Types.ObjectId,
      ref: "Funnel",
    },

    // Пользовательские данные
    createdBy: String, // В будущем можно заменить на ObjectId ref на User
    lastModifiedBy: String,

    // Статистика
    usage: {
      totalViews: { type: Number, default: 0, min: 0 },
      totalCompletions: { type: Number, default: 0, min: 0 },
      lastUsed: Date,
    },

    // Timestamps
    publishedAt: Date,
  },
  {
    timestamps: true, // Автоматически добавляет createdAt и updatedAt
    collection: "funnels",
  }
);

// Индексы для производительности
FunnelSchema.index({ "funnelData.meta.id": 1 }); // Для поиска по ID воронки
FunnelSchema.index({ status: 1, updatedAt: -1 }); // Для каталога воронок
FunnelSchema.index({ name: "text", description: "text" }); // Для поиска по тексту
FunnelSchema.index({ createdBy: 1 }); // Для фильтра по автору
FunnelSchema.index({ "usage.lastUsed": -1 }); // Для сортировки по использованию

// Методы модели
FunnelSchema.methods.toPublicJSON = function (this: IFunnel) {
  return {
    _id: this._id,
    name: this.name,
    description: this.description,
    status: this.status,
    version: this.version,
    createdAt: this.createdAt,
    updatedAt: this.updatedAt,
    publishedAt: this.publishedAt,
    usage: this.usage,
    funnelData: this.funnelData,
  };
};

FunnelSchema.methods.incrementUsage = function (
  this: IFunnel,
  type: "view" | "completion"
) {
  if (type === "view") {
    this.usage.totalViews += 1;
  } else if (type === "completion") {
    this.usage.totalCompletions += 1;
  }
  this.usage.lastUsed = new Date();
  return this.save();
};

// Статические методы
FunnelSchema.statics.findPublished = function () {
  return this.find({ status: "published" }).sort({ publishedAt: -1 });
};

FunnelSchema.statics.findByFunnelId = function (funnelId: string) {
  return this.findOne({ "funnelData.meta.id": funnelId });
};

// Pre-save хуки
FunnelSchema.pre("save", function (next) {
  // Автоматически устанавливаем publishedAt при первой публикации
  if (this.status === "published" && !this.publishedAt) {
    this.publishedAt = new Date();
  }

  // Валидация: firstScreenId должен существовать в screens
  if (this.funnelData.meta.firstScreenId) {
    const firstScreenExists = this.funnelData.screens.some(
      (screen) => screen.id === this.funnelData.meta.firstScreenId
    );
    if (!firstScreenExists) {
      return next(new Error("firstScreenId must reference an existing screen"));
    }
  }

  next();
});

// Экспорт модели с проверкой на существование
// В dev окружении пересоздаём модель, чтобы подтянуть изменения схемы (enums и т.п.)
if (
  process.env.NODE_ENV !== "production" &&
  typeof mongoose.models.Funnel !== "undefined"
) {
  try {
    (
      mongoose as unknown as { deleteModel: (name: string) => void }
    ).deleteModel("Funnel");
  } catch {
    // no-op
  }
}

const FunnelModel: Model<IFunnel> =
  mongoose.models.Funnel || mongoose.model<IFunnel>("Funnel", FunnelSchema);

export default FunnelModel;
