/**
 * 客户级承运商官网登录账密 — 密码加密落库，Worker 运行时解密
 */
import { prisma } from "@/lib/prisma";
import {
  decryptSecret,
  encryptSecret,
} from "@/modules/customer/token-crypto";

export type ProviderCredentialProvider = "mothership" | "flock";

export type ProviderLogin = {
  email: string;
  password: string;
};

export type ProviderCredentialDto = {
  provider: ProviderCredentialProvider;
  email: string | null;
  has_password: boolean;
  updated_at: string | null;
};

/** 管理端查看：回传完整邮箱与解密后的密码（仅 GET） */
export type ProviderCredentialAdminViewDto = ProviderCredentialDto & {
  password: string | null;
};

const PROVIDERS: ProviderCredentialProvider[] = ["mothership", "flock"];

export function isProviderCredentialProvider(
  raw: unknown,
): raw is ProviderCredentialProvider {
  return raw === "mothership" || raw === "flock";
}

function maskEmail(email: string): string {
  const at = email.indexOf("@");
  if (at <= 1) {
    return "***";
  }
  return `${email.slice(0, 2)}***${email.slice(at)}`;
}

export function serializeProviderCredentialDto(row: {
  provider: string;
  loginEmail: string;
  passwordCiphertext: string;
  updatedAt: Date;
  isDeleted: boolean;
}): ProviderCredentialDto {
  return {
    provider: row.provider as ProviderCredentialProvider,
    email: row.isDeleted ? null : maskEmail(row.loginEmail),
    has_password: !row.isDeleted && Boolean(row.passwordCiphertext),
    updated_at: row.isDeleted ? null : row.updatedAt.toISOString(),
  };
}

export function serializeProviderCredentialAdminView(row: {
  provider: string;
  loginEmail: string;
  passwordCiphertext: string;
  updatedAt: Date;
  isDeleted: boolean;
}): ProviderCredentialAdminViewDto {
  if (row.isDeleted) {
    return {
      provider: row.provider as ProviderCredentialProvider,
      email: null,
      password: null,
      has_password: false,
      updated_at: null,
    };
  }
  const password = decryptSecret(row.passwordCiphertext);
  const email = row.loginEmail.trim() || null;
  return {
    provider: row.provider as ProviderCredentialProvider,
    email,
    password: password && !password.startsWith("cleared:") ? password : null,
    has_password: Boolean(email && password && !password.startsWith("cleared:")),
    updated_at: row.updatedAt.toISOString(),
  };
}

export async function listCustomerProviderCredentials(
  customerId: string,
): Promise<ProviderCredentialDto[]> {
  const rows = await prisma.customerProviderCredential.findMany({
    where: { customerId, isDeleted: false },
  });
  const byProvider = new Map(rows.map((r) => [r.provider, r]));
  return PROVIDERS.map((provider) => {
    const row = byProvider.get(provider);
    if (!row) {
      return {
        provider,
        email: null,
        has_password: false,
        updated_at: null,
      };
    }
    return serializeProviderCredentialDto(row);
  });
}

/** 管理端查看账密：完整邮箱 + 明文密码 */
export async function listCustomerProviderCredentialsForAdmin(
  customerId: string,
): Promise<ProviderCredentialAdminViewDto[]> {
  const rows = await prisma.customerProviderCredential.findMany({
    where: { customerId, isDeleted: false },
  });
  const byProvider = new Map(rows.map((r) => [r.provider, r]));
  return PROVIDERS.map((provider) => {
    const row = byProvider.get(provider);
    if (!row) {
      return {
        provider,
        email: null,
        password: null,
        has_password: false,
        updated_at: null,
      };
    }
    return serializeProviderCredentialAdminView(row);
  });
}

/** Worker 用：解密后的明文登录（无记录返回 null） */
export async function getCustomerProviderLogin(
  customerId: string,
  provider: ProviderCredentialProvider,
): Promise<ProviderLogin | null> {
  const row = await prisma.customerProviderCredential.findUnique({
    where: {
      customerId_provider: { customerId, provider },
    },
  });
  if (!row || row.isDeleted) {
    return null;
  }
  const password = decryptSecret(row.passwordCiphertext);
  if (!password || !row.loginEmail.trim()) {
    return null;
  }
  return { email: row.loginEmail.trim(), password };
}

/** 库中是否已配置该承运商账密（不论能否解密） */
export async function hasCustomerProviderCredential(
  customerId: string,
  provider: ProviderCredentialProvider,
): Promise<boolean> {
  const row = await prisma.customerProviderCredential.findUnique({
    where: {
      customerId_provider: { customerId, provider },
    },
    select: { isDeleted: true, passwordCiphertext: true, loginEmail: true },
  });
  return Boolean(
    row &&
      !row.isDeleted &&
      row.loginEmail.trim() &&
      row.passwordCiphertext,
  );
}

export async function upsertCustomerProviderCredential(
  customerId: string,
  provider: ProviderCredentialProvider,
  input: { email: string; password?: string; updatedBy?: string },
): Promise<ProviderCredentialDto> {
  const email = input.email.trim();
  if (!email || !email.includes("@")) {
    throw new Error("登录邮箱无效");
  }

  const existing = await prisma.customerProviderCredential.findUnique({
    where: { customerId_provider: { customerId, provider } },
  });

  const passwordTrimmed = input.password?.trim() ?? "";
  if (!existing && !passwordTrimmed) {
    throw new Error("首次配置必须填写密码");
  }
  if (existing && !existing.isDeleted && !passwordTrimmed) {
    const row = await prisma.customerProviderCredential.update({
      where: { customerId_provider: { customerId, provider } },
      data: {
        loginEmail: email,
        updatedBy: input.updatedBy ?? null,
        isDeleted: false,
      },
    });
    return serializeProviderCredentialDto(row);
  }

  const ciphertext = encryptSecret(passwordTrimmed);
  const row = await prisma.customerProviderCredential.upsert({
    where: { customerId_provider: { customerId, provider } },
    create: {
      customerId,
      provider,
      loginEmail: email,
      passwordCiphertext: ciphertext,
      updatedBy: input.updatedBy ?? null,
      isDeleted: false,
    },
    update: {
      loginEmail: email,
      passwordCiphertext: ciphertext,
      updatedBy: input.updatedBy ?? null,
      isDeleted: false,
    },
  });
  return serializeProviderCredentialDto(row);
}

export async function clearCustomerProviderCredential(
  customerId: string,
  provider: ProviderCredentialProvider,
  updatedBy?: string,
): Promise<ProviderCredentialDto> {
  const existing = await prisma.customerProviderCredential.findUnique({
    where: { customerId_provider: { customerId, provider } },
  });
  if (!existing) {
    return {
      provider,
      email: null,
      has_password: false,
      updated_at: null,
    };
  }
  const row = await prisma.customerProviderCredential.update({
    where: { customerId_provider: { customerId, provider } },
    data: {
      isDeleted: true,
      updatedBy: updatedBy ?? null,
      passwordCiphertext: encryptSecret(`cleared:${Date.now()}`),
    },
  });
  return serializeProviderCredentialDto({ ...row, isDeleted: true });
}
