import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm";
import { getDb } from "@/core/db/client";
import { architectProfiles, tenants } from "@/core/db/schema";
import { getStorage } from "@/core/storage/storage";
import type { TenantContext } from "@/core/tenant/types";

export type ProfileUpdateInput = {
  studioName?: string;
  description?: string;
  tagline?: string;
  about?: string;
  architectName?: string;
  architectTitle?: string;
  architectPhotoStorageKey?: string | null;
  philosophy?: string;
  vision?: string;
  mission?: string;
  approach?: string;
  designPrinciples?: string;
  experience?: string;
  studioCulture?: string;
  workspace?: string;
  methodology?: string;
  collaborations?: string;
  location?: string;
  foundedYear?: number | null;
  websiteUrl?: string;
  publicEmail?: string;
  phone?: string;
  whatsapp?: string;
  businessHours?: string;
  mapEmbedUrl?: string;
  socialLinks?: Record<string, string>;
  seoTitle?: string;
  seoDescription?: string;
};

function trimOrNull(value?: string) {
  const v = value?.trim();
  return v ? v : null;
}

export async function getArchitectProfile(ctx: TenantContext) {
  const db = getDb();
  const [profile] = await db
    .select()
    .from(architectProfiles)
    .where(eq(architectProfiles.tenantId, ctx.tenantId))
    .limit(1);

  const [tenant] = await db
    .select({
      studioName: tenants.studioName,
      description: tenants.description,
      slug: tenants.slug,
    })
    .from(tenants)
    .where(eq(tenants.id, ctx.tenantId))
    .limit(1);

  return {
    tenant: tenant ?? null,
    profile: profile ?? null,
  };
}

export async function updateArchitectProfile(
  ctx: TenantContext,
  input: ProfileUpdateInput,
) {
  const db = getDb();

  if (input.studioName !== undefined || input.description !== undefined) {
    await db
      .update(tenants)
      .set({
        ...(input.studioName !== undefined
          ? { studioName: input.studioName.trim() }
          : {}),
        ...(input.description !== undefined
          ? { description: input.description.trim() || null }
          : {}),
        updatedAt: new Date(),
      })
      .where(eq(tenants.id, ctx.tenantId));
  }

  const [existing] = await db
    .select({ id: architectProfiles.id })
    .from(architectProfiles)
    .where(eq(architectProfiles.tenantId, ctx.tenantId))
    .limit(1);

  const profileFields = {
    tagline: trimOrNull(input.tagline),
    about: trimOrNull(input.about),
    architectName: trimOrNull(input.architectName),
    architectTitle: trimOrNull(input.architectTitle),
    ...(input.architectPhotoStorageKey !== undefined
      ? { architectPhotoStorageKey: input.architectPhotoStorageKey }
      : {}),
    philosophy: trimOrNull(input.philosophy),
    vision: trimOrNull(input.vision),
    mission: trimOrNull(input.mission),
    approach: trimOrNull(input.approach),
    designPrinciples: trimOrNull(input.designPrinciples),
    experience: trimOrNull(input.experience),
    studioCulture: trimOrNull(input.studioCulture),
    workspace: trimOrNull(input.workspace),
    methodology: trimOrNull(input.methodology),
    collaborations: trimOrNull(input.collaborations),
    location: trimOrNull(input.location),
    foundedYear: input.foundedYear ?? null,
    websiteUrl: trimOrNull(input.websiteUrl),
    publicEmail: trimOrNull(input.publicEmail),
    phone: trimOrNull(input.phone),
    whatsapp: trimOrNull(input.whatsapp),
    businessHours: trimOrNull(input.businessHours),
    mapEmbedUrl: trimOrNull(input.mapEmbedUrl),
    ...(input.socialLinks !== undefined
      ? { socialLinks: input.socialLinks }
      : {}),
    seoTitle: trimOrNull(input.seoTitle),
    seoDescription: trimOrNull(input.seoDescription),
    updatedAt: new Date(),
  };

  if (!existing) {
    const [created] = await db
      .insert(architectProfiles)
      .values({
        tenantId: ctx.tenantId,
        ...profileFields,
      })
      .returning();
    return created;
  }

  const [updated] = await db
    .update(architectProfiles)
    .set(profileFields)
    .where(eq(architectProfiles.tenantId, ctx.tenantId))
    .returning();

  return updated ?? null;
}

const ARCHITECT_PHOTO_MIME = new Set([
  "image/jpeg",
  "image/png",
  "image/webp",
  "image/avif",
]);

const ARCHITECT_PHOTO_MAX_BYTES = 8 * 1024 * 1024;

export async function setArchitectPhoto(
  ctx: TenantContext,
  input: {
    fileName: string;
    mimeType: string;
    body: Buffer;
  },
) {
  if (!ARCHITECT_PHOTO_MIME.has(input.mimeType)) {
    return { ok: false as const, error: "Use a JPEG, PNG, WebP, or AVIF image" };
  }
  if (
    input.body.byteLength <= 0 ||
    input.body.byteLength > ARCHITECT_PHOTO_MAX_BYTES
  ) {
    return { ok: false as const, error: "Photo must be under 8MB" };
  }

  const assetId = randomUUID();
  const storage = getStorage();
  const db = getDb();

  const { profile } = await getArchitectProfile(ctx);
  const previousKey = profile?.architectPhotoStorageKey ?? null;

  const uploaded = await storage.uploadAsset({
    tenantId: ctx.tenantId,
    assetId,
    body: input.body,
    mimeType: input.mimeType,
    fileName: input.fileName,
  });

  if (profile) {
    await db
      .update(architectProfiles)
      .set({
        architectPhotoStorageKey: uploaded.storageKey,
        updatedAt: new Date(),
      })
      .where(eq(architectProfiles.tenantId, ctx.tenantId));
  } else {
    await db.insert(architectProfiles).values({
      tenantId: ctx.tenantId,
      architectPhotoStorageKey: uploaded.storageKey,
    });
  }

  if (previousKey && previousKey !== uploaded.storageKey) {
    try {
      await storage.deleteAsset(previousKey, ctx.tenantId);
    } catch {
      // Best-effort cleanup
    }
  }

  return { ok: true as const, storageKey: uploaded.storageKey };
}

export async function clearArchitectPhoto(ctx: TenantContext) {
  const storage = getStorage();
  const db = getDb();

  const { profile } = await getArchitectProfile(ctx);
  const previousKey = profile?.architectPhotoStorageKey ?? null;

  if (profile) {
    await db
      .update(architectProfiles)
      .set({
        architectPhotoStorageKey: null,
        updatedAt: new Date(),
      })
      .where(eq(architectProfiles.tenantId, ctx.tenantId));
  }

  if (previousKey) {
    try {
      await storage.deleteAsset(previousKey, ctx.tenantId);
    } catch {
      // Best-effort cleanup
    }
  }

  return { ok: true as const };
}
