import { eq, desc, and, ne } from 'drizzle-orm';
import { db } from './client';
import { campaigns, workspaces, users, type Campaign, type Workspace } from './schema';

/**
 * Ein Draft ist semantisch eine Campaign mit status='draft'. Diese Repo-Schicht
 * trennt die Draft-Sicht klar vom Versand-Workflow:
 *  - Drafts sind editier-/auto-save-fähig.
 *  - Drafts können beliebig oft mutieren ohne Versions-Historie aufzubauen
 *    (Versionierung läuft separat in version-repo).
 *  - Sobald die Campaign in den Versand geht, fällt sie aus der Draft-Sicht raus.
 */

export interface DraftSummary {
  id: string;
  name: string;
  status: Campaign['status'];
  workspaceId: string;
  workspaceSlug: string;
  brandName: string;
  brandPrimaryColor: string;
  updatedAt: Date;
  createdAt: Date;
  hasOutput: boolean;
}

export interface DraftFull extends DraftSummary {
  briefingJson: object;
  tiptapJson: object;
  strategyJson: object | null;
  spamScore: number | null;
  spamVerdict: Campaign['spamVerdict'];
  spamReportJson: object | null;
}

export interface DraftCreateInput {
  workspaceId: string;
  name?: string;
  briefingJson?: object;
  tiptapJson?: object;
}

export interface DraftUpdateInput {
  name?: string;
  briefingJson?: object;
  tiptapJson?: object;
  strategyJson?: object | null;
  spamScore?: number | null;
  spamVerdict?: Campaign['spamVerdict'];
  spamReportJson?: object | null;
  workspaceId?: string;
}

/** Erzeugt bei Bedarf einen Default-User (Single-User-Setup, Auth folgt später). */
function getOrCreateDefaultUserId(): string {
  const existing = db.select().from(users).limit(1).get()?.id;
  if (existing) return existing;
  const id = crypto.randomUUID();
  db.insert(users).values({ id, email: 'admin@mailforge.local', role: 'admin' }).run();
  return id;
}

function joinBrand(c: Campaign, b: Workspace): DraftSummary {
  const hasOutput = !!c.strategyJson && !!(c.strategyJson as { _generated?: unknown })._generated;
  return {
    id: c.id,
    name: c.name,
    status: c.status,
    workspaceId: c.workspaceId,
    workspaceSlug: b.slug,
    brandName: b.name,
    brandPrimaryColor: b.primaryColor,
    updatedAt: c.updatedAt,
    createdAt: c.createdAt,
    hasOutput,
  };
}

export function createDraft(input: DraftCreateInput): DraftSummary {
  const userId = getOrCreateDefaultUserId();
  const workspace = db.select().from(workspaces).where(eq(workspaces.id, input.workspaceId)).get();
  if (!workspace) throw new Error(`Unknown workspaceId: ${input.workspaceId}`);

  const id = crypto.randomUUID();
  db.insert(campaigns).values({
    id,
    workspaceId: input.workspaceId,
    createdById: userId,
    name: input.name ?? 'Unbenannter Entwurf',
    briefingJson: input.briefingJson ?? {},
    tiptapJson: input.tiptapJson ?? {},
    status: 'draft',
  }).run();

  const created = db.select().from(campaigns).where(eq(campaigns.id, id)).get()!;
  return joinBrand(created, workspace);
}

export function updateDraft(id: string, patch: DraftUpdateInput): DraftSummary | undefined {
  const existing = db.select().from(campaigns).where(eq(campaigns.id, id)).get();
  if (!existing) return undefined;

  // Nur explizit gesetzte Felder schreiben — undefined heisst "nicht ändern"
  const update: Partial<Campaign> & { updatedAt: Date } = { updatedAt: new Date() };
  if (patch.name !== undefined) update.name = patch.name;
  if (patch.briefingJson !== undefined) update.briefingJson = patch.briefingJson;
  if (patch.tiptapJson !== undefined) update.tiptapJson = patch.tiptapJson;
  if (patch.strategyJson !== undefined) update.strategyJson = patch.strategyJson;
  if (patch.spamScore !== undefined) update.spamScore = patch.spamScore;
  if (patch.spamVerdict !== undefined) update.spamVerdict = patch.spamVerdict;
  if (patch.spamReportJson !== undefined) update.spamReportJson = patch.spamReportJson;
  if (patch.workspaceId !== undefined) update.workspaceId = patch.workspaceId;

  db.update(campaigns).set(update).where(eq(campaigns.id, id)).run();

  const updated = db.select().from(campaigns).where(eq(campaigns.id, id)).get()!;
  const workspace = db.select().from(workspaces).where(eq(workspaces.id, updated.workspaceId)).get()!;
  return joinBrand(updated, workspace);
}

export function getDraft(id: string): DraftFull | undefined {
  const c = db.select().from(campaigns).where(eq(campaigns.id, id)).get();
  if (!c) return undefined;
  const workspace = db.select().from(workspaces).where(eq(workspaces.id, c.workspaceId)).get();
  if (!workspace) return undefined;
  const summary = joinBrand(c, workspace);
  return {
    ...summary,
    briefingJson: (c.briefingJson as object) ?? {},
    tiptapJson: (c.tiptapJson as object) ?? {},
    strategyJson: (c.strategyJson as object) ?? null,
    spamScore: c.spamScore,
    spamVerdict: c.spamVerdict,
    spamReportJson: (c.spamReportJson as object) ?? null,
  };
}

export function deleteDraft(id: string): boolean {
  const result = db.delete(campaigns).where(eq(campaigns.id, id)).run();
  return result.changes > 0;
}

/** Liste aller Drafts (alles ausser 'sent'/'sending'/'cancelled') sortiert nach updatedAt desc. */
export function listDrafts(): DraftSummary[] {
  // Wir zeigen Drafts + Review/Building/Failed in der Sidebar — sent/sending/cancelled fliegen raus
  const rows = db.select({
    c: campaigns,
    b: workspaces,
  })
    .from(campaigns)
    .innerJoin(workspaces, eq(campaigns.workspaceId, workspaces.id))
    .where(and(
      ne(campaigns.status, 'sent'),
      ne(campaigns.status, 'sending'),
      ne(campaigns.status, 'cancelled'),
    ))
    .orderBy(desc(campaigns.updatedAt))
    .all();

  return rows.map((r) => joinBrand(r.c, r.b));
}

/** Top-N nach updatedAt — für die "Zuletzt verwendet"-Sektion. */
export function listRecentDrafts(limit = 5): DraftSummary[] {
  return listDrafts().slice(0, limit);
}

/** Gruppiert Drafts nach Workspace — für die "Projekte"-Sektion. */
export function listDraftsGroupedByBrand(): Array<{
  workspaceId: string;
  workspaceSlug: string;
  brandName: string;
  brandPrimaryColor: string;
  drafts: DraftSummary[];
}> {
  const all = listDrafts();
  const allBrands = db.select().from(workspaces).all();
  return allBrands.map((b) => ({
    workspaceId: b.id,
    workspaceSlug: b.slug,
    brandName: b.name,
    brandPrimaryColor: b.primaryColor,
    drafts: all.filter((d) => d.workspaceId === b.id),
  }));
}

/** Dupliziert einen Draft — für "Als Kopie öffnen". */
export function duplicateDraft(id: string): DraftSummary | undefined {
  const src = db.select().from(campaigns).where(eq(campaigns.id, id)).get();
  if (!src) return undefined;
  return createDraft({
    workspaceId: src.workspaceId,
    name: `${src.name} (Kopie)`,
    briefingJson: (src.briefingJson as object) ?? {},
    tiptapJson: (src.tiptapJson as object) ?? {},
  });
}
