import { and, eq, inArray } from "drizzle-orm";

import { db } from "./db";
import { appConfig, mediaAsset, mediaUsage } from "./db/schema";
export const MAINTENANCE_MODE_KEY = "maintenance_mode";
export {
  SITE_NAME_KEY,
  SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY,
  SITE_SETTINGS_ENTITY_ID,
  SITE_SETTINGS_ENTITY_TYPE,
  SITE_SETTINGS_FAVICON_FIELD_KEY,
  SITE_SETTINGS_LOGO_DARK_FIELD_KEY,
  SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY,
  SITE_SETTINGS_KEY,
  DEFAULT_SITE_NAME,
  buildDefaultSiteSettings,
  getDefaultSiteSettingsMediaBindings,
  parseSiteSettingsValue,
  type SiteSettings,
  type SiteSettingsMediaBindings,
} from "./site-settings";
export {
  MAIL_SETTINGS_KEY,
  buildDefaultMailSettings,
  parseMailSettingsValue,
  toMailSettingsFormValues,
  type MailSettings,
  type MailSettingsFormValues,
} from "./mail-settings";
export {
  MARQUEE_SETTINGS_KEY,
  buildDefaultMarqueeSettings,
  parseMarqueeSettingsValue,
  splitMarqueeRowItems,
  syncMarqueeSettingsToGermanSource,
  type MarqueeLocaleSettings,
  type MarqueeSettings,
} from "./marquee-settings";
import {
  DEFAULT_SITE_NAME,
  SITE_NAME_KEY,
  SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY,
  SITE_SETTINGS_ENTITY_ID,
  SITE_SETTINGS_ENTITY_TYPE,
  SITE_SETTINGS_FAVICON_FIELD_KEY,
  SITE_SETTINGS_LOGO_DARK_FIELD_KEY,
  SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY,
  SITE_SETTINGS_KEY,
  buildDefaultSiteSettings,
  getDefaultSiteSettingsMediaBindings,
  parseSiteSettingsValue,
  type SiteSettings,
  type SiteSettingsMediaBindings,
} from "./site-settings";
import {
  MAIL_SETTINGS_KEY,
  buildDefaultMailSettings,
  parseMailSettingsValue,
  toMailSettingsFormValues,
  type MailSettings,
  type MailSettingsFormValues,
} from "./mail-settings";
import {
  MARQUEE_SETTINGS_KEY,
  buildDefaultMarqueeSettings,
  parseMarqueeSettingsValue,
  syncMarqueeSettingsToGermanSource,
  type MarqueeSettings,
} from "./marquee-settings";

// Small helpers over the app_config key/value table (Drizzle).
async function readConfigValue(key: string): Promise<string | undefined> {
  const [row] = await db
    .select({ value: appConfig.value })
    .from(appConfig)
    .where(eq(appConfig.key, key))
    .limit(1);

  return row?.value;
}

async function upsertConfig(key: string, value: string): Promise<void> {
  await db
    .insert(appConfig)
    .values({ key, value })
    .onConflictDoUpdate({ target: appConfig.key, set: { value } });
}

export async function getMaintenanceMode(): Promise<boolean> {
  try {
    return (await readConfigValue(MAINTENANCE_MODE_KEY)) === "true";
  } catch {
    return false;
  }
}

export async function setMaintenanceMode(enabled: boolean): Promise<void> {
  await upsertConfig(MAINTENANCE_MODE_KEY, enabled ? "true" : "false");
}

export async function getSiteSettings(): Promise<SiteSettings> {
  try {
    const configs = await db
      .select({ key: appConfig.key, value: appConfig.value })
      .from(appConfig)
      .where(inArray(appConfig.key, [SITE_SETTINGS_KEY, SITE_NAME_KEY]));

    const configMap = new Map(configs.map((config) => [config.key, config.value]));
    const fallbackName = configMap.get(SITE_NAME_KEY) ?? DEFAULT_SITE_NAME;

    return parseSiteSettingsValue(configMap.get(SITE_SETTINGS_KEY), fallbackName);
  } catch {
    return buildDefaultSiteSettings();
  }
}

export async function updateSiteSettings(settings: SiteSettings): Promise<void> {
  await upsertConfig(SITE_SETTINGS_KEY, JSON.stringify(settings));
}

export async function getMailSettings(): Promise<MailSettings> {
  try {
    return parseMailSettingsValue(await readConfigValue(MAIL_SETTINGS_KEY));
  } catch {
    return buildDefaultMailSettings();
  }
}

export async function getMailSettingsFormValues(): Promise<MailSettingsFormValues> {
  const settings = await getMailSettings();

  return toMailSettingsFormValues(settings);
}

export async function updateMailSettings(settings: MailSettings): Promise<void> {
  await upsertConfig(MAIL_SETTINGS_KEY, JSON.stringify(settings));
}

export async function getMarqueeSettings(): Promise<MarqueeSettings> {
  try {
    return parseMarqueeSettingsValue(await readConfigValue(MARQUEE_SETTINGS_KEY));
  } catch {
    return buildDefaultMarqueeSettings();
  }
}

export async function updateMarqueeSettings(settings: MarqueeSettings): Promise<void> {
  const normalizedSettings = syncMarqueeSettingsToGermanSource(settings);

  await upsertConfig(MARQUEE_SETTINGS_KEY, JSON.stringify(normalizedSettings));
}

export async function getSiteSettingsMediaBindings(): Promise<SiteSettingsMediaBindings> {
  try {
    const usages = await db
      .select({
        fieldKey: mediaUsage.fieldKey,
        updatedAt: mediaUsage.updatedAt,
        assetId: mediaAsset.id,
        assetUrl: mediaAsset.url,
      })
      .from(mediaUsage)
      .innerJoin(mediaAsset, eq(mediaAsset.id, mediaUsage.assetId))
      .where(
        and(
          eq(mediaUsage.entityType, SITE_SETTINGS_ENTITY_TYPE),
          eq(mediaUsage.entityId, SITE_SETTINGS_ENTITY_ID),
        ),
      );

    return usages.reduce<SiteSettingsMediaBindings>((result, usage) => {
      const binding = {
        assetId: usage.assetId,
        url: usage.assetUrl,
        version: usage.updatedAt.toISOString(),
      };

      if (usage.fieldKey === SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY) {
        result.siteLogoLight = binding;
      }

      if (usage.fieldKey === SITE_SETTINGS_LOGO_DARK_FIELD_KEY) {
        result.siteLogoDark = binding;
      }

      if (usage.fieldKey === SITE_SETTINGS_FAVICON_FIELD_KEY) {
        result.favicon = binding;
      }

      if (usage.fieldKey === SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY) {
        result.defaultOgImage = binding;
      }

      return result;
    }, getDefaultSiteSettingsMediaBindings());
  } catch {
    return getDefaultSiteSettingsMediaBindings();
  }
}
