// Cloudflare Worker 入口: fetch（API+静的） / scheduled（Cron スケジューラ）
import { createApp } from "./app.js";
import { runScheduler } from "./core.js";
import { D1Store } from "./d1store.js";
import { DryRunMailer, ResendMailer, type Mailer } from "./mailer.js";
import {
  DryRunSmsSender,
  NttCPaaSSmsSender,
  TwilioSmsSender,
  type SmsSender,
} from "./sms.js";
import type { RuntimeConfig } from "./types.js";

export interface Env {
  DB: D1Database;
  ASSETS: Fetcher;
  ADMIN_PASSWORD: string;
  SESSION_SECRET: string;
  RESEND_API_KEY?: string;
  RESEND_WEBHOOK_SECRET?: string;
  MAIL_FROM: string;
  SENDER_INFO: string;
  DRY_RUN?: string;
  MAX_SENDS_PER_TICK?: string;
  MAX_SENDS_PER_DAY?: string;
  APP_BASE_URL?: string;
  // --- v4: SMS ---
  /** none | nttcpaas（= nttcpath）| twilio（none で全SMS送信が skipped になる = ロールバック手段） */
  SMS_PROVIDER?: string;
  /** SMS実送信ゲート（既定 true）。メールの DRY_RUN とは独立 */
  SMS_DRY_RUN?: string;
  MAX_SMS_PER_TICK?: string;
  MAX_SMS_PER_DAY?: string;
  /** 管理画面のコスト概算表示に使う円単価（1セグメントあたり） */
  SMS_COST_PER_SEGMENT?: string;
  /** SMS本文に載せる短い送信者名（未設定なら SENDER_INFO。住所等は停止ページで表示） */
  SMS_SENDER_INFO?: string;
  /** SMSの配信停止URLに使う短いベースURL（未設定なら APP_BASE_URL） */
  SMS_BASE_URL?: string;
  /** NTT C-Path / NTT CPaaS（推奨） */
  NTT_CPAAS_API_KEY?: string;
  /** ポータルに表示されるテナント固有のAPIベースURL（例: yourtenant.ibapi.nttcpaas.com） */
  NTT_CPAAS_API_BASE?: string;
  /** 配信レポート(DLR)の通知先URL（任意・P2で利用） */
  NTT_CPAAS_NOTIFY_URL?: string;
  TWILIO_ACCOUNT_SID?: string;
  TWILIO_AUTH_TOKEN?: string;
  /** 送信元。NTT CPaaS はトライアル中 ServiceSMS / Twilio は E.164 の番号 */
  SMS_FROM?: string;
}

function buildConfig(env: Env, baseUrl: string): RuntimeConfig {
  const dryRun = (env.DRY_RUN ?? "true").toLowerCase() !== "false";
  const smsDryRun = (env.SMS_DRY_RUN ?? "true").toLowerCase() !== "false";
  return {
    dryRun,
    mailFrom: env.MAIL_FROM ?? "onboarding@resend.dev",
    senderInfo: env.SENDER_INFO ?? "",
    maxSendsPerTick: Number(env.MAX_SENDS_PER_TICK ?? "100"),
    maxSendsPerDay: Number(env.MAX_SENDS_PER_DAY ?? "2000"),
    appBaseUrl: baseUrl,
    smsDryRun,
    maxSmsPerTick: Number(env.MAX_SMS_PER_TICK ?? "20"),
    maxSmsPerDay: Number(env.MAX_SMS_PER_DAY ?? "100"),
    smsCostPerSegment: Number(env.SMS_COST_PER_SEGMENT ?? "10"),
    smsSenderInfo: env.SMS_SENDER_INFO ?? "",
    smsBaseUrl: env.SMS_BASE_URL ?? "",
  };
}

function buildMailer(env: Env, dryRun: boolean): Mailer {
  if (dryRun || !env.RESEND_API_KEY) return new DryRunMailer();
  return new ResendMailer(env.RESEND_API_KEY);
}

/**
 * SMS送信アダプタを組み立てる。
 * 設定が不完全なときは必ず DryRunSmsSender に落として実送信させない（安全側）。
 */
function buildSmsSender(env: Env, smsDryRun: boolean): SmsSender {
  const provider = (env.SMS_PROVIDER ?? "none").toLowerCase();
  if (smsDryRun || provider === "none") return new DryRunSmsSender();
  // 「NTT C-Path」「NTT CPaaS」は同一サービスの呼称違いなのでどちらの綴りも受け付ける
  if (
    (provider === "nttcpaas" || provider === "nttcpath" || provider === "ntt-c-path") &&
    env.NTT_CPAAS_API_KEY &&
    env.NTT_CPAAS_API_BASE
  )
    return new NttCPaaSSmsSender(
      env.NTT_CPAAS_API_KEY,
      env.NTT_CPAAS_API_BASE,
      env.SMS_FROM || "ServiceSMS", // トライアル中の既定送信元
      env.NTT_CPAAS_NOTIFY_URL,
    );
  if (
    provider === "twilio" &&
    env.TWILIO_ACCOUNT_SID &&
    env.TWILIO_AUTH_TOKEN &&
    env.SMS_FROM
  )
    return new TwilioSmsSender(
      env.TWILIO_ACCOUNT_SID,
      env.TWILIO_AUTH_TOKEN,
      env.SMS_FROM,
    );
  // 設定が不完全なときは必ず DryRun に落とす（設定漏れで実送信してしまう事故を構造的に防ぐ）
  return new DryRunSmsSender();
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    const baseUrl = env.APP_BASE_URL ?? url.origin;
    const cfg = buildConfig(env, baseUrl);
    const store = new D1Store(env.DB);
    const mailer = buildMailer(env, cfg.dryRun);
    const smsSender = buildSmsSender(env, cfg.smsDryRun);

    const isAppRoute =
      url.pathname.startsWith("/api") ||
      url.pathname.startsWith("/f/") ||
      url.pathname.startsWith("/u/") ||
      url.pathname.startsWith("/t/") ||
      url.pathname.startsWith("/p/");

    if (isAppRoute) {
      const app = createApp({
        store,
        mailer,
        smsSender,
        cfg,
        adminPassword: env.ADMIN_PASSWORD ?? "",
        sessionSecret: env.SESSION_SECRET ?? "",
        resendWebhookSecret: env.RESEND_WEBHOOK_SECRET,
      });
      return app.fetch(request, env, ctx);
    }
    // 静的ダッシュボード（public/）
    return env.ASSETS.fetch(request);
  },

  async scheduled(_event: ScheduledController, env: Env, _ctx: ExecutionContext): Promise<void> {
    const baseUrl = env.APP_BASE_URL ?? "";
    const cfg = buildConfig(env, baseUrl);
    const store = new D1Store(env.DB);
    const mailer = buildMailer(env, cfg.dryRun);
    const smsSender = buildSmsSender(env, cfg.smsDryRun);
    const summary = await runScheduler(store, mailer, cfg, Date.now(), smsSender);
    await store.audit(
      "scheduler",
      `live=${summary.live} smsLive=${summary.smsLive} bc=${summary.broadcastSends} step=${summary.stepSends} sms=${summary.smsSends} skip=${summary.skipped} fail=${summary.failed}`,
    );
  },
};
