import { CloseBotClient, ok, err } from "../client.js";
import type { ToolDefinition, ToolResult, AgencyDto, BalanceDto, BillingOptionsDto, UpdateBillingConfigInput, ReBillingDto, ReBillingUpdateInput, TransactionDto, BilledUsageDto, AddSourceTransactionDto } from "../types.js";

export const tools: ToolDefinition[] = [
  {
    name: "get_agency",
    description: "Get the current agency details",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "list_agencies",
    description: "List all agencies the account is part of (currently max 1)",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "get_usage",
    description: "Get agency usage across scopes: bots, storage, users, responses",
    inputSchema: {
      type: "object",
      properties: {
        scopes: {
          type: "string",
          description: "Comma-separated scopes (default: bots,storage,users,responses)",
        },
      },
    },
  },
  {
    name: "invite_users",
    description: "Invite users to the agency",
    inputSchema: {
      type: "object",
      properties: {
        invites: {
          type: "array",
          description: "Array of invite objects",
          items: {
            type: "object",
            properties: {
              email: { type: "string", description: "Email to invite" },
              role: { type: "string", description: "Role (admin, member, etc.)" },
              sourceIds: { type: "array", items: { type: "string" }, description: "Source IDs to give access" },
            },
          },
        },
      },
      required: ["invites"],
    },
  },
  {
    name: "revoke_invitation",
    description: "Revoke an invitation by email",
    inputSchema: {
      type: "object",
      properties: {
        email: { type: "string", description: "The email to revoke invitation for" },
      },
      required: ["email"],
    },
  },
  {
    name: "get_balance",
    description: "Get the agency wallet balance",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "get_source_balance",
    description: "Get the balance for a specific source",
    inputSchema: {
      type: "object",
      properties: {
        sourceId: { type: "string", description: "The source ID" },
      },
      required: ["sourceId"],
    },
  },
  {
    name: "get_billing_options",
    description: "Get agency billing configuration (auto-refill, thresholds, etc.)",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "update_billing",
    description: "Update agency billing configuration",
    inputSchema: {
      type: "object",
      properties: {
        overBillingEnabled: { type: "boolean", description: "Enable over-billing" },
        autoRefillEnabled: { type: "boolean", description: "Enable auto-refill" },
        topUpAmount: { type: "number", description: "Top-up amount (smallest currency unit)" },
        refillThreshold: { type: "number", description: "Refill threshold (smallest currency unit)" },
      },
    },
  },
  {
    name: "list_transactions",
    description: "List agency transactions with optional status filter and pagination",
    inputSchema: {
      type: "object",
      properties: {
        status: { type: "string", description: "Filter by status: pending, succeeded, failed" },
        page: { type: "number", description: "Page number (default 1)" },
        pageSize: { type: "number", description: "Page size (default 20)" },
      },
    },
  },
  {
    name: "list_source_transactions",
    description: "List transactions for a specific source",
    inputSchema: {
      type: "object",
      properties: {
        sourceId: { type: "string", description: "The source ID" },
        status: { type: "string", description: "Filter: pending, succeeded, failed" },
        page: { type: "number", description: "Page number" },
        pageSize: { type: "number", description: "Page size" },
      },
      required: ["sourceId"],
    },
  },
  {
    name: "add_source_transaction",
    description: "Add a manual transaction to a source wallet",
    inputSchema: {
      type: "object",
      properties: {
        sourceId: { type: "string", description: "The source ID" },
        amount: { type: "string", description: "Transaction amount" },
        description: { type: "string", description: "Transaction description" },
      },
      required: ["sourceId", "amount"],
    },
  },
  {
    name: "delete_source_transaction",
    description: "Delete a source transaction",
    inputSchema: {
      type: "object",
      properties: {
        sourceId: { type: "string", description: "The source ID" },
        id: { type: "number", description: "Transaction ID" },
      },
      required: ["sourceId", "id"],
    },
  },
  {
    name: "list_billed_usages",
    description: "List billed usage records for a time range",
    inputSchema: {
      type: "object",
      properties: {
        startTime: { type: "string", description: "Start time (ISO 8601)" },
        endTime: { type: "string", description: "End time (ISO 8601)" },
      },
    },
  },
  {
    name: "get_rebilling",
    description: "Get re-billing settings (response, storage, user costs and token multiplier)",
    inputSchema: { type: "object", properties: {} },
  },
  {
    name: "update_rebilling",
    description: "Update re-billing settings",
    inputSchema: {
      type: "object",
      properties: {
        enabled: { type: "boolean", description: "Enable re-billing" },
        responseCost: { type: "string", description: "Response unit cost" },
        storageCost: { type: "string", description: "Storage unit cost" },
        userCost: { type: "string", description: "User unit cost" },
        tokenMultiplier: { type: "string", description: "Token multiplier" },
      },
    },
  },
  {
    name: "refill_agency_wallet",
    description: "⚠️ Charges your payment method to refill the agency wallet. Use with caution.",
    inputSchema: {
      type: "object",
      properties: {
        amount: { type: "number", description: "Amount to refill (smallest currency unit)" },
        currency: { type: "string", description: "Currency code (e.g., usd)" },
      },
      required: ["amount"],
    },
  },
  {
    name: "refill_source_wallet",
    description: "⚠️ Charges your payment method to refill a source wallet. Use with caution.",
    inputSchema: {
      type: "object",
      properties: {
        sourceId: { type: "string", description: "The source ID" },
        amount: { type: "number", description: "Amount to refill" },
        currency: { type: "string", description: "Currency code" },
      },
      required: ["sourceId", "amount"],
    },
  },
];

export async function handler(
  client: CloseBotClient,
  name: string,
  args: Record<string, unknown>
): Promise<ToolResult> {
  try {
    switch (name) {
      case "get_agency":
        return ok(await client.get<AgencyDto>("/agency/current"));

      case "list_agencies":
        return ok(await client.get<AgencyDto[]>("/agency"));

      case "get_usage":
        return ok(
          await client.get("/agency/usage", { scopes: args.scopes })
        );

      case "invite_users":
        return ok(
          await client.post("/agency/invite", { invites: args.invites })
        );

      case "revoke_invitation":
        return ok(
          await client.delete("/agency/invite", { email: args.email })
        );

      case "get_balance":
        return ok(await client.get<BalanceDto>("/agency/billing/balance"));

      case "get_source_balance":
        return ok(
          await client.get<BalanceDto>(
            `/agency/billing/balance/source/${args.sourceId}`
          )
        );

      case "get_billing_options":
        return ok(
          await client.get<BillingOptionsDto>("/agency/billing/options")
        );

      case "update_billing": {
        const body: UpdateBillingConfigInput = {};
        if (args.overBillingEnabled !== undefined)
          body.overBillingEnabled = args.overBillingEnabled as boolean;
        if (args.autoRefillEnabled !== undefined)
          body.autoRefillEnabled = args.autoRefillEnabled as boolean;
        if (args.topUpAmount !== undefined)
          body.topUpAmount = args.topUpAmount as number;
        if (args.refillThreshold !== undefined)
          body.refillThreshold = args.refillThreshold as number;
        return ok(
          await client.put<BillingOptionsDto>("/agency/billing/options", body)
        );
      }

      case "list_transactions":
        return ok(
          await client.get<TransactionDto[]>("/agency/billing/transactions", {
            status: args.status,
            page: args.page,
            pageSize: args.pageSize,
          })
        );

      case "list_source_transactions":
        return ok(
          await client.get<TransactionDto[]>(
            `/agency/billing/transactions/source/${args.sourceId}`,
            {
              status: args.status,
              page: args.page,
              pageSize: args.pageSize,
            }
          )
        );

      case "add_source_transaction": {
        const body: AddSourceTransactionDto = {
          amount: args.amount as string,
          description: args.description as string | undefined,
        };
        return ok(
          await client.post<TransactionDto>(
            `/agency/billing/transactions/source/${args.sourceId}`,
            body
          )
        );
      }

      case "delete_source_transaction":
        return ok(
          await client.delete(
            `/agency/billing/transactions/source/${args.sourceId}/${args.id}`
          )
        );

      case "list_billed_usages":
        return ok(
          await client.get<BilledUsageDto[]>("/agency/billing/usages", {
            startTime: args.startTime,
            endTime: args.endTime,
          })
        );

      case "get_rebilling":
        return ok(
          await client.get<ReBillingDto>("/agency/billing/re-billing")
        );

      case "update_rebilling": {
        const body: ReBillingUpdateInput = {};
        if (args.enabled !== undefined) body.enabled = args.enabled as boolean;
        if (args.responseCost !== undefined)
          body.responseCost = args.responseCost as string;
        if (args.storageCost !== undefined)
          body.storageCost = args.storageCost as string;
        if (args.userCost !== undefined)
          body.userCost = args.userCost as string;
        if (args.tokenMultiplier !== undefined)
          body.tokenMultiplier = args.tokenMultiplier as string;
        return ok(
          await client.put("/agency/billing/re-billing", body)
        );
      }

      case "refill_agency_wallet":
        return ok(
          await client.post("/agency/billing/refill", {
            amount: args.amount,
            currency: args.currency,
          })
        );

      case "refill_source_wallet":
        return ok(
          await client.post(
            `/agency/billing/refill/source/${args.sourceId}`,
            { amount: args.amount, currency: args.currency }
          )
        );

      default:
        return err(`Unknown tool: ${name}`);
    }
  } catch (error) {
    return err(error);
  }
}
