import type {
  IntegrationProvider,
  CardData,
  TestResult,
  PushResult,
  ExternalField,
  JsonValue,
} from "../types";

const SHEETS_API = "https://sheets.googleapis.com/v4/spreadsheets";

interface GSheetsConfig {
  accessToken: string;
  refreshToken?: string;
  tokenExpiresAt?: number;
  spreadsheetId: string;
  sheetName: string;
}

function parseConfig(config: JsonValue): GSheetsConfig {
  const c = config as Record<string, unknown>;
  return {
    accessToken: (c.accessToken as string) || "",
    refreshToken: (c.refreshToken as string) || undefined,
    tokenExpiresAt: (c.tokenExpiresAt as number) || undefined,
    spreadsheetId: (c.spreadsheetId as string) || "",
    sheetName: (c.sheetName as string) || "Sheet1",
  };
}

async function sheetsFetch(
  accessToken: string,
  path: string,
  options: RequestInit = {}
) {
  const res = await fetch(`${SHEETS_API}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
      ...(options.headers || {}),
    },
  });
  if (!res.ok) {
    const text = await res.text().catch(() => "");
    throw new Error(`Google Sheets API ${res.status}: ${text}`);
  }
  return res.json();
}

export const googleSheetsProvider: IntegrationProvider = {
  id: "google_sheets",
  name: "Google Sheets",
  description: "Append response cards as rows in Google Sheets",
  icon: "google_sheets",
  category: "spreadsheet",
  supportsFieldMapping: true,
  supportsOAuth: true,
  configFields: [
    {
      key: "spreadsheetId",
      label: "Spreadsheet ID",
      type: "text",
      required: true,
      placeholder: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
      helpText: "Found in the spreadsheet URL between /d/ and /edit",
    },
    {
      key: "sheetName",
      label: "Sheet Name",
      type: "text",
      placeholder: "Sheet1",
      helpText: "The tab name to append rows to",
    },
  ],

  setupGuide: {
    summary:
      "Google Sheets uses OAuth 2.0. You'll create a project in Google Cloud Console, enable the Sheets API, and register OAuth credentials. Then churches can click Connect to authorize Echo OCR against their own Google account.",
    docsUrl: "https://developers.google.com/sheets/api/quickstart/js",
    steps: [
      {
        title: "Create a Google Cloud project",
        body: "Go to Google Cloud Console and create a new project (or select an existing one). Projects are free.",
        linkUrl: "https://console.cloud.google.com/projectcreate",
        linkLabel: "Create a project",
      },
      {
        title: "Enable the Google Sheets API",
        body: "Open the API Library and search for \"Google Sheets API\", then click Enable.",
        linkUrl: "https://console.cloud.google.com/apis/library/sheets.googleapis.com",
        linkLabel: "Enable Sheets API",
      },
      {
        title: "Configure the OAuth consent screen",
        body: "Under APIs & Services → OAuth consent screen, choose External, fill in the app name, user support email, and developer email. Add your domain under Authorized Domains.",
      },
      {
        title: "Add scopes",
        body: "On the Scopes step, add https://www.googleapis.com/auth/spreadsheets. This lets Echo OCR read sheet headers and append rows.",
      },
      {
        title: "Create OAuth Client ID credentials",
        body: "Under APIs & Services → Credentials, click Create Credentials → OAuth client ID. Choose \"Web application\".",
        linkUrl: "https://console.cloud.google.com/apis/credentials",
        linkLabel: "Open Credentials",
      },
      {
        title: "Set the Authorized Redirect URI",
        body: "Add https://YOUR_DOMAIN/api/integrations/oauth/google_sheets/callback (replace YOUR_DOMAIN with the URL where Echo OCR is hosted). For local dev, add http://localhost:3000/api/integrations/oauth/google_sheets/callback.",
      },
      {
        title: "Copy the Client ID and Secret",
        body: "After creating the client, copy the Client ID and Client Secret into Echo OCR's environment as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, then restart the server.",
      },
      {
        title: "Find the Spreadsheet ID",
        body: "Open the target Google Sheet in your browser. The URL looks like https://docs.google.com/spreadsheets/d/ABC123/edit — the ABC123 portion is your Spreadsheet ID.",
      },
      {
        title: "Connect from the Integrations page",
        body: "Click Connect next to Google Sheets in Echo OCR and sign in with the Google account that owns (or has edit access to) the spreadsheet.",
      },
    ],
  },

  async testConnection(config: JsonValue): Promise<TestResult> {
    try {
      const { accessToken, spreadsheetId } = parseConfig(config);
      if (!accessToken) {
        return {
          success: false,
          message: "Not connected — use the Connect button to authorize with Google",
        };
      }
      if (!spreadsheetId) {
        return { success: false, message: "Spreadsheet ID is required" };
      }
      const data = await sheetsFetch(
        accessToken,
        `/${spreadsheetId}?fields=properties.title,sheets.properties.title`
      );
      const title = data.properties?.title || "Unknown";
      const sheetCount = data.sheets?.length ?? 0;
      return {
        success: true,
        message: `Connected to "${title}" (${sheetCount} sheets)`,
      };
    } catch (err) {
      return {
        success: false,
        message: err instanceof Error ? err.message : "Connection failed",
      };
    }
  },

  async getExternalFields(config: JsonValue): Promise<ExternalField[]> {
    try {
      const { accessToken, spreadsheetId, sheetName } = parseConfig(config);
      const range = `${sheetName || "Sheet1"}!1:1`;
      const data = await sheetsFetch(
        accessToken,
        `/${spreadsheetId}/values/${encodeURIComponent(range)}`
      );
      const headers = data.values?.[0] || [];
      return headers.map((h: string, i: number) => ({
        id: String(i),
        name: h,
        type: "text",
      }));
    } catch {
      return [];
    }
  },

  async pushCard(
    card: CardData,
    config: JsonValue,
    mapping: JsonValue
  ): Promise<PushResult> {
    try {
      const { accessToken, spreadsheetId, sheetName } = parseConfig(config);
      if (!accessToken || !spreadsheetId) {
        return { success: false, message: "Google Sheets not configured" };
      }

      const fieldMap = (mapping as Record<string, string>) || {};
      const headerRange = `${sheetName || "Sheet1"}!1:1`;
      const headerData = await sheetsFetch(
        accessToken,
        `/${spreadsheetId}/values/${encodeURIComponent(headerRange)}`
      );
      const headers: string[] = headerData.values?.[0] || [];

      const row: string[] = headers.map((header) => {
        const cardField = Object.entries(fieldMap).find(
          ([, ext]) => ext === header
        )?.[0];
        if (!cardField) return "";
        const val = card[cardField];
        if (val === null || val === undefined) return "";
        return typeof val === "object" ? JSON.stringify(val) : String(val);
      });

      const range = `${sheetName || "Sheet1"}!A:A`;
      await sheetsFetch(
        accessToken,
        `/${spreadsheetId}/values/${encodeURIComponent(range)}:append?valueInputOption=USER_ENTERED`,
        {
          method: "POST",
          body: JSON.stringify({ values: [row] }),
        }
      );

      return { success: true, message: "Row appended to sheet" };
    } catch (err) {
      return {
        success: false,
        message: err instanceof Error ? err.message : "Push failed",
      };
    }
  },
};
