
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Google Integration
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//


// Tracks whether write-only credentials are already stored; set by LoadGoogleIntegrationSettings.
// Used by ValidateGoogleIntegrationFields so blank write-only fields aren't flagged as missing.
var bGoogleHasServiceAccount = false;
var bGoogleHasOAuth2         = false;


// Opens the Google Integration credentials dialog and loads current settings from the server.
// Private key and client secret are never returned by the server - those fields show a
// placeholder so the user knows a value is already stored without seeing the secret itself.
function OpenGoogleIntegrationDialog() {
    var nDlgWidth = Math.min(660, $(window).width() - 40);

    $("#igDialogGoogleIntegration").igDialog({
        modal: true, headerText: "Google Integration", width: nDlgWidth, height: 940,
        resizable: false, closeOnEscape: true, openAnimation: "", closeAnimation: "fade"
    });
    $("#igDialogGoogleIntegration").igDialog("open");

    $("#GoogleIntegrationSaveButton").unbind().click(function () { OnGoogleIntegrationSave(); });
    $("#GoogleIntegrationCloseButton").unbind().click(function () { CloseGoogleIntegrationDialog(); });
    $("#GoogleIntegrationConnectButton").unbind().click(function () { OnGoogleIntegrationSave(OpenGoogleAccountDialog); });
    $("#GoogleIntegrationHelpButton").unbind().click(function () { PopupMessageBox("Google Sheets - Service Account", GetServiceAccountJsonKeyHelpText()); });
    $("#GoogleIntegrationOpenConsoleButton").unbind().click(function () { window.open("https://console.cloud.google.com"); });
    $("#GoogleIntegrationOAuthHelpButton").unbind().click(function () { PopupMessageBox("Google Sheets - OAuth2 App", GetOAuth2AppHelpText()); });
    $("#GoogleIntegrationOAuthOpenConsoleButton").unbind().click(function () { window.open("https://console.cloud.google.com"); });
    $("#GoogleIntegrationAuthTypeHelpButton").unbind().click(function () { PopupMessageBox("Google Sheets - Auth Type", GetAuthTypeHelpText()); });
    $("#GoogleIntegrationCopyRedirectUri").unbind().click(function () {
        var sUri = $("#GoogleIntegrationOAuthRedirectUri").val();
        navigator.clipboard.writeText(sUri).then(function () {
            ToastMessage("Google Integration", "Redirect URI copied to clipboard.");
        }, function (err) {
            console.error("GoogleIntegration clipboard copy failed: " + err);
        });
    });
    $("#GoogleIntegrationAuthType").unbind("change").change(function () { ApplyGoogleIntegrationAuthType(); $("#GoogleIntegrationStatusDiv").hide(); });

    // Clear field highlight as soon as the user starts correcting it
    $("#GoogleIntegrationSaClientEmail, #GoogleIntegrationSaPrivateKey, #GoogleIntegrationSaProjectId," +
      "#GoogleIntegrationOAuthClientId, #GoogleIntegrationOAuthClientSecret")
        .off("input").on("input", function () { $(this).css("outline", ""); });

    $("#GoogleIntegrationStatusDiv").hide();
    LoadGoogleIntegrationSettings();
}

function CloseGoogleIntegrationDialog() {
    $("#igDialogGoogleIntegration").igDialog("close");
}

function ApplyGoogleIntegrationAuthType() {
    var nAuthType = parseInt($("#GoogleIntegrationAuthType").val(), 10);
    var bServiceAccount = (nAuthType === 1 || nAuthType === 3);
    var bOAuth          = (nAuthType === 2 || nAuthType === 3);
    $("#GoogleIntegrationServiceAccountFieldset").toggle(bServiceAccount);
    $("#GoogleIntegrationOAuthFieldset").toggle(bOAuth);
    $("#GoogleIntegrationPersonalFieldset").toggle(bOAuth);
    ClearGoogleIntegrationHighlights();
}

function ClearGoogleIntegrationHighlights() {
    $("#GoogleIntegrationSaClientEmail, #GoogleIntegrationSaPrivateKey, #GoogleIntegrationSaProjectId," +
      "#GoogleIntegrationOAuthClientId, #GoogleIntegrationOAuthClientSecret")
        .css("outline", "");
}

// Returns true if all fields required by the current auth type are filled.
// Highlights any missing fields in red and returns false if validation fails.
function ValidateGoogleIntegrationFields() {
    var nAuthType       = parseInt($("#GoogleIntegrationAuthType").val(), 10);
    var bServiceAccount = (nAuthType === 1 || nAuthType === 3);
    var bOAuth          = (nAuthType === 2 || nAuthType === 3);
    var sOutline        = "2px solid red";
    var bValid          = true;

    ClearGoogleIntegrationHighlights();

    if (bServiceAccount) {
        if (!$("#GoogleIntegrationSaClientEmail").val().trim())
            { $("#GoogleIntegrationSaClientEmail").css("outline", sOutline); bValid = false; }
        if (!bGoogleHasServiceAccount && !$("#GoogleIntegrationSaPrivateKey").val().trim())
            { $("#GoogleIntegrationSaPrivateKey").css("outline", sOutline); bValid = false; }
        if (!$("#GoogleIntegrationSaProjectId").val().trim())
            { $("#GoogleIntegrationSaProjectId").css("outline", sOutline); bValid = false; }
    }
    if (bOAuth) {
        if (!$("#GoogleIntegrationOAuthClientId").val().trim())
            { $("#GoogleIntegrationOAuthClientId").css("outline", sOutline); bValid = false; }
        if (!bGoogleHasOAuth2 && !$("#GoogleIntegrationOAuthClientSecret").val().trim())
            { $("#GoogleIntegrationOAuthClientSecret").css("outline", sOutline); bValid = false; }
    }

    return bValid;
}

// Fetches current settings and pre-fills non-secret fields.
function LoadGoogleIntegrationSettings() {
    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetGoogleIntegrationSettings",
        type: "GET",
        success: function (response) {
            if (!response.Success) { console.error("GoogleIntegration load failed: " + response.ErrorResults); ToastError("Google Integration", response.ErrorResults); return; }

            bGoogleHasServiceAccount = !!response.HasServiceAccount;
            bGoogleHasOAuth2         = !!response.HasOAuth2;
            console.log("GoogleIntegration loaded: AuthType=" + response.AuthType +
                ", HasServiceAccount=" + response.HasServiceAccount +
                ", HasOAuth2=" + response.HasOAuth2 +
                ", RedirectUri=" + response.ComputedRedirectUri);
            $("#GoogleIntegrationAuthType").val(response.AuthType);
            ApplyGoogleIntegrationAuthType();
            $("#GoogleIntegrationSaClientEmail").val(response.SaClientEmail);
            $("#GoogleIntegrationSaProjectId").val(response.SaProjectId);
            $("#GoogleIntegrationOAuthClientId").val(response.OAuthClientId);
            $("#GoogleIntegrationOAuthRedirectUri").val(response.ComputedRedirectUri);

            // Private key and client secret are write-only - show placeholder text when a value exists
            $("#GoogleIntegrationSaPrivateKey").attr("placeholder",
                response.HasServiceAccount ? "Private key already stored - paste new key to replace" : "Paste -----BEGIN RSA PRIVATE KEY----- block here");
            $("#GoogleIntegrationOAuthClientSecret").attr("placeholder",
                response.HasOAuth2 ? "Client secret already stored - enter new value to replace" : "Leave blank to keep existing");
        },
        error: function (xhr) { console.error("GoogleIntegration load HTTP error: " + xhr.status + " " + xhr.statusText); ToastError("Google Integration", "Error " + xhr.status + ", " + xhr.statusText); }
    });
}

// Collects field values and posts them to the server.
// Blank private key / client secret means "keep the existing value" - the server handles that.
// Optional fnCallback is called after a successful save (e.g. to chain OnConnectGoogleAccount).
function OnGoogleIntegrationSave(fnCallback) {
    if (!ValidateGoogleIntegrationFields()) return;

    var nAuthType          = parseInt($("#GoogleIntegrationAuthType").val(), 10);
    var sSaClientEmail     = $("#GoogleIntegrationSaClientEmail").val().trim();
    var sSaPrivateKey      = $("#GoogleIntegrationSaPrivateKey").val().trim();
    var sSaProjectId       = $("#GoogleIntegrationSaProjectId").val().trim();
    var sOAuthClientId     = $("#GoogleIntegrationOAuthClientId").val().trim();
    var sOAuthClientSecret = $("#GoogleIntegrationOAuthClientSecret").val().trim();

    $("#GoogleIntegrationSaveButton").prop("disabled", true).val("Saving...");

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxSaveGoogleIntegrationSettings",
        type: "POST",
        data: JSON.stringify({
            nAuthType: nAuthType,
            sSaClientEmail: sSaClientEmail, sSaPrivateKey: sSaPrivateKey, sSaProjectId: sSaProjectId,
            sOAuthClientId: sOAuthClientId, sOAuthClientSecret: sOAuthClientSecret
        }),
        contentType: "application/json",
        success: function (response) {
            $("#GoogleIntegrationSaveButton").prop("disabled", false).val("Save");
            if (response.Success) {
                console.log("GoogleIntegration save succeeded.");
                ShowGoogleIntegrationStatus("Settings saved!");
                // Clear write-only fields so they don't re-submit stale values on next save
                $("#GoogleIntegrationSaPrivateKey").val("");
                $("#GoogleIntegrationOAuthClientSecret").val("");
                LoadGoogleIntegrationSettings();
                if (typeof fnCallback === "function") fnCallback();
            } else {
                console.error("GoogleIntegration save failed: " + response.ErrorResults);
                ToastError("Google Integration", response.ErrorResults);
            }
        },
        error: function (xhr) {
            console.error("GoogleIntegration save HTTP error: " + xhr.status + " " + xhr.statusText);
            $("#GoogleIntegrationSaveButton").prop("disabled", false).val("Save");
            ToastError("Google Integration", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}

function ShowGoogleIntegrationStatus(sMessage) {
    $("#GoogleIntegrationStatusLabel").text(sMessage);
    $("#GoogleIntegrationStatusDiv").show();
}


var GOOGLE_EXPORT_PREFS_KEY = "st-google-export-prefs";

function LoadGoogleExportPrefs() {
    try {
        var sJson = localStorage.getItem(GOOGLE_EXPORT_PREFS_KEY);
        // null means the key was never written — use defaults including the default folder.
        // An empty string sDriveFolder in stored JSON means the user explicitly cleared it.
        if (sJson !== null) return JSON.parse(sJson);
    } catch (e) {}
    return { bRemember: false, bAddDate: false, sDriveFolder: "Standard Time Exports", bOverride: false };
}

function SaveGoogleExportPrefs(prefs) {
    try { localStorage.setItem(GOOGLE_EXPORT_PREFS_KEY, JSON.stringify(prefs)); } catch (e) {}
}

// Called from File > Export > Google Sheets (clickhandler = "OnExportGoogleSheets(e)").
// If the user previously checked "Remember these settings" and is not holding Alt,
// skips the dialog and exports with saved preferences.  Alt always forces the dialog.
function OnExportGoogleSheets(event) {
    var bAltHeld = !!(event && event.altKey);
    var prefs    = LoadGoogleExportPrefs();

    if (prefs.bRemember && !bAltHeld) {
        DoGoogleSheetsExport("", prefs.bAddDate, prefs.sDriveFolder, prefs.bOverride);
    } else {
        OpenGoogleExportDialog(prefs);
    }
}

function OpenGoogleExportDialog(prefs) {
    var nDlgWidth = Math.min(560, $(window).width() - 40);

    $("#igDialogGoogleExport").igDialog({
        modal: true, headerText: "Export to Google Sheets", width: nDlgWidth, height: 430,
        resizable: false, closeOnEscape: true, openAnimation: "", closeAnimation: "fade"
    });

    $("#GoogleExportSheetName").val(GetSelectedContentTitle() || "");
    $("#GoogleExportAddDate").prop("checked", !!prefs.bAddDate);
    $("#GoogleExportDriveFolder").val(prefs.sDriveFolder || "");
    $("#GoogleExportOverride").prop("checked", !!prefs.bOverride);
    $("#GoogleExportRememberSettings").prop("checked", !!prefs.bRemember);

    $("#igDialogGoogleExport").igDialog("open");
    $("#GoogleExportSheetName").focus().select();

    $("#GoogleExportButton").unbind().click(function () { OnGoogleExportDialogExport(); });
    $("#GoogleExportCancelButton").unbind().click(function () { CloseGoogleExportDialog(); });
    $("#GoogleExportSheetName").off("keydown").on("keydown", function (e) {
        if (e.which === 13) { OnGoogleExportDialogExport(); }
    });
}

function CloseGoogleExportDialog() {
    $("#igDialogGoogleExport").igDialog("close");
}

function OnGoogleExportDialogExport() {
    var sSheetName   = $("#GoogleExportSheetName").val().trim();
    var bAddDate     = $("#GoogleExportAddDate").is(":checked");
    var sDriveFolder = $("#GoogleExportDriveFolder").val().trim();
    var bOverride    = $("#GoogleExportOverride").is(":checked");
    var bRemember    = $("#GoogleExportRememberSettings").is(":checked");

    SaveGoogleExportPrefs({ bRemember: bRemember, bAddDate: bAddDate, sDriveFolder: sDriveFolder, bOverride: bOverride });
    CloseGoogleExportDialog();
    DoGoogleSheetsExport(sSheetName, bAddDate, sDriveFolder, bOverride);
}

// Builds a user-facing message for the ServiceCredsConfigured === false case.
// Uses the diag fields the server always includes on that response path so the
// message reflects the specific gap (nothing configured, account not connected, etc.).
function BuildGoogleCredsErrorMessage(response) {
    var nAuthType       = response.DiagAuthType;
    var bHasOAuth2      = !!response.DiagHasOAuth2;
    var bHasServiceAcct = !!response.DiagHasServiceAccount;
    var bHasUserTokens  = !!response.DiagHasUserTokens;

    // Service account auth type selected but no service account credentials stored
    if (nAuthType === 1 && !bHasServiceAcct)
        return "Service account credentials are not configured. Add the service account email and private key in the dialog below.";

    // OAuth2 auth type selected; app credentials are set up but this user has not connected their account
    if (nAuthType === 2 && bHasOAuth2 && !bHasUserTokens)
        return "Your Google account is not connected. You must sign in with Google once so this app can export sheets on your behalf. Click \"Connect Google Account\" in the dialog below to complete the one-time sign-in.";

    // OAuth2 auth type selected but the OAuth2 app itself is not configured
    if (nAuthType === 2 && !bHasOAuth2)
        return "OAuth2 app credentials are not configured. Add a Client ID and Client Secret in the dialog below.";

    // Both auth types selected; OAuth2 app exists but account not connected, and no service account
    if (nAuthType === 3 && bHasOAuth2 && !bHasUserTokens && !bHasServiceAcct)
        return "Your Google account is not connected and no service account is configured. Connect your account or add service account credentials in the dialog below.";

    // Both auth types selected but nothing at all is configured
    if (nAuthType === 3 && !bHasOAuth2 && !bHasServiceAcct)
        return "No Google credentials are configured. Add a service account or set up an OAuth2 app in the dialog below.";

    // Fallback: use the server-supplied message
    return response.ErrorResults || "No Google credentials are configured. Set up a service account or connect your Google account in the dialog below.";
}

// Sends the export request to the server.  sSheetName may be empty to fall back to ContentTitle.
function DoGoogleSheetsExport(sSheetName, bAddDate, sDriveFolder, bOverride) {
    var ContentType        = GetSelectedContentType();
    var ContentTitle       = GetSelectedContentTitle();
    var ValueString        = GetSelectedContentPaneValueString();
    var LayoutString       = LoadSelectedPaneLayoutStringFromCookie();
    var FilterJsonString   = LoadSelectedPaneFilterJsonStringFromCookie();
    var SettingsJsonString = LoadSelectedPaneSettingsJsonStringFromCookie();

    OpenPleaseWaitDialog("Export");

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxExportContentToGoogleSheets",
        type: "POST",
        data: JSON.stringify({
            ContentType: ContentType, ContentTitle: ContentTitle,
            ValueString: ValueString, LayoutString: LayoutString,
            FilterJsonString: FilterJsonString, SettingsJsonString: SettingsJsonString,
            SheetName: sSheetName, bAddDateSuffix: bAddDate,
            DriveFolderName: sDriveFolder, bOverrideExisting: bOverride
        }),
        contentType: "application/json",
        success: function (response) {
            ClosePleaseWaitDialog();
            if (response.Success) {
                console.log("GoogleSheets export succeeded: " + response.SheetUrl);
                // Delay opening the new tab so the Please Wait fade animation completes first.
                // window.open immediately backgrounds this tab, which pauses Chrome's animations.
                var sSheetUrl = response.SheetUrl;
                setTimeout(function () { window.open(sSheetUrl, "_blank"); }, 500);
                ToastMessage("Export", response.bOverrideApplied ? "Google Sheet updated." : "Google Sheet created.");
            } else {
                var sError = response.ErrorResults || "";
                console.error("GoogleSheets export failed: " + sError);
                if (response.DiagAuthType !== undefined)
                    LogGoogleExportDiag(response);
                else if (response.DiagnosticInfo)
                    console.error("GoogleSheets export diag: " + response.DiagnosticInfo);
                if (response.ServiceCredsConfigured === false) {
                    ToastError("Export to Google Sheets", BuildGoogleCredsErrorMessage(response));
                    OpenGoogleIntegrationDialog();
                } else {
                    ToastError("Export to Google Sheets", sError);
                }
            }
        },
        error: function (xhr) {
            ClosePleaseWaitDialog();
            console.error("GoogleSheets export HTTP error: " + xhr.status + " " + xhr.statusText);
            ToastError("Export to Google Sheets", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}


// Initiates the Google OAuth2 consent flow by asking the server for the consent URL,
// then opening it in a named 600x700 popup. The popup navigates through Google's
// consent screen and lands on GoogleOAuthCallback, which closes it and notifies this tab.
function OnConnectGoogleAccount() {
    $.ajax({
        url: VirtualDirectory + "/Home/AjaxBeginGoogleOAuth",
        type: "POST",
        data: JSON.stringify({}),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                console.log("GoogleOAuth consent flow started: " + response.AuthUrl);
                // Named window reuses an existing popup if the user clicks twice
                window.open(response.AuthUrl, "GoogleOAuth", "width=600,height=700");
            } else {
                console.error("GoogleOAuth begin failed: " + response.ErrorResults);
                ToastError("Google Sign-In", response.ErrorResults);
            }
        },
        error: function (xhr) {
            console.error("GoogleOAuth begin HTTP error: " + xhr.status + " " + xhr.statusText);
            ToastError("Google Sign-In", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}


// Logs a human-readable breakdown of Google export diagnostic fields returned by the server.
function LogGoogleExportDiag(response) {
    var sAuthTypeLabels = { 0: "None — export disabled", 1: "Service Account", 2: "OAuth2 (per-user)", 3: "Both" };
    var sAuthTypeLabel  = sAuthTypeLabels[response.DiagAuthType] || "Unknown (" + response.DiagAuthType + ")";

    console.group("GoogleSheets export diagnostic");
    console.log("Auth Type: "            + response.DiagAuthType        + " = " + sAuthTypeLabel);
    console.log("Has User Tokens: "      + response.DiagHasUserTokens   + (response.DiagHasUserTokens
        ? " — personal Google account is connected, OAuth2 tokens are stored"
        : " — user has not connected their Google account; go to Tools > Google Integration and click Connect Google Account"));
    console.log("Has Service Account: "  + response.DiagHasServiceAccount + (response.DiagHasServiceAccount
        ? " — service account credentials (email, key, project) are configured"
        : " — no service account configured; set Auth Type to Service Account or Both and save credentials"));
    console.log("Has OAuth2: "           + response.DiagHasOAuth2       + (response.DiagHasOAuth2
        ? " — OAuth2 app credentials (Client ID and Secret) are saved"
        : " — OAuth2 app credentials not saved; set Auth Type to OAuth2 or Both and enter Client ID and Secret"));
    console.log("User ID: "              + response.DiagUserId          + " — the user record checked for stored Google tokens");
    console.groupEnd();
}


// Opens the per-user Google Account connection dialog and loads current token status.
// Typically called as the callback after OnGoogleIntegrationSave() so credentials are
// always saved before the user attempts to connect.
function OpenGoogleAccountDialog() {
    var nDlgWidth = Math.min(460, $(window).width() - 40);

    $("#igDialogGoogleAccount").igDialog({
        modal: true, headerText: "Google Account", width: nDlgWidth, height: 350,
        resizable: false, closeOnEscape: true, openAnimation: "", closeAnimation: "fade"
    });
    $("#igDialogGoogleAccount").igDialog("open");

$("#GoogleAccountConnectButton").unbind().click(function () { OnConnectGoogleAccount(); });
    $("#GoogleAccountClearButton").unbind().click(function () { OnClearGoogleAccount(); });
    $("#GoogleAccountCloseButton").unbind().click(function () { CloseGoogleAccountDialog(); });

    LoadGoogleAccountStatus();
}

function CloseGoogleAccountDialog() {
    $("#igDialogGoogleAccount").igDialog("close");
}

// Fetches connection status from the server and updates the dialog UI.
function LoadGoogleAccountStatus() {
    $("#GoogleAccountStatusLabel").text("Checking...");
    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetGoogleAccountStatus",
        type: "GET",
        success: function (response) {
            if (!response.Success) {
                console.error("GoogleAccount status failed: " + response.ErrorResults);
                $("#GoogleAccountStatusLabel").text("Error: " + response.ErrorResults);
                return;
            }
            var bConnected = !!response.Connected;
            console.log("GoogleAccount status: Connected=" + bConnected);
            $("#GoogleAccountStatusLabel").text(bConnected ? "Connected" : "Not connected");
            if (bConnected) {
                $("#GoogleAccountStatusDiv").css({ "background-color": "var(--st-bg-toolbar, #f0f8e8)", "border-color": "var(--st-accent, #8bc34a)" });
                $("#GoogleAccountClearButton").show();
            } else {
                $("#GoogleAccountStatusDiv").css({ "background-color": "var(--st-bg-toolbar, #f5f5f5)", "border-color": "var(--st-border, #ccc)" });
                $("#GoogleAccountClearButton").hide();
            }
        },
        error: function (xhr) {
            console.error("GoogleAccount status HTTP error: " + xhr.status + " " + xhr.statusText);
            $("#GoogleAccountStatusLabel").text("Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}

// Clears the current user's Google OAuth2 tokens and refreshes the dialog status.
function OnClearGoogleAccount() {
    $.ajax({
        url: VirtualDirectory + "/Home/AjaxClearGoogleTokens",
        type: "POST",
        data: JSON.stringify({}),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                console.log("GoogleAccount tokens cleared.");
                ToastMessage("Google Account", "Google account disconnected.");
                LoadGoogleAccountStatus();
            } else {
                console.error("GoogleAccount clear failed: " + response.ErrorResults);
                ToastError("Google Account", response.ErrorResults);
            }
        },
        error: function (xhr) {
            console.error("GoogleAccount clear HTTP error: " + xhr.status + " " + xhr.statusText);
            ToastError("Google Account", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}


// Returns help text explaining when to use each auth type option.
function GetAuthTypeHelpText() {
    return "Which auth type should I choose?\n\n" +
        "None\n" +
        "Google Sheets export is disabled. Choose this if you have not set up Google credentials yet.\n\n" +
        "Service Account\n" +
        "Best for automated or scheduled exports where no user interaction is required. " +
        APP_NAME + " uses a shared Google identity (the service account) to create sheets and shares " +
        "them with the user's email automatically. Requires a JSON key file from Google Cloud Console. " +
        "Choose this if you want a simple setup that works for all users without individual sign-in.\n\n" +
        "OAuth2\n" +
        "Lets each user connect their own Google account. Exports go directly into that user's Drive " +
        "under their own identity - no sharing step needed. Requires an OAuth2 app to be configured " +
        "in Google Cloud Console. Choose this if users want exports in their own Drive, or if a shared " +
        "service account is not permitted by your organization's Google Workspace policy.\n\n" +
        "Both\n" +
        "Supports both methods at once. When a user has connected their Google account, their personal " +
        "OAuth2 tokens are used. For users who have not connected, the service account is used as a " +
        "fallback and the sheet is shared with them automatically. Choose this for the most flexibility.";
}


// Returns the "What is a service account JSON key file?" help block for use in dialogs.
function GetServiceAccountJsonKeyHelpText() {
    return "What is a Google Cloud service account JSON key file?\n\n" +
        "A service account is a special Google identity that an application uses to access Google APIs without\n" +
        "requiring a user to log in. The JSON key file is a credential file you download from Google Cloud Console\n" +
        "that proves your application is allowed to act as that service account. It contains a client email address,\n" +
        "a private key, and a project ID - " + APP_NAME + " uses these three values to authenticate with the\n" +
        "Google Sheets and Google Drive APIs when creating and sharing spreadsheets.\n\n" +
        "Note: Google may require a billing account to activate a project, even for free-tier APIs.\n" +
        "The Google Sheets and Drive APIs do not charge for normal usage, but a credit card on file\n" +
        "may be required before Google will allow you to enable APIs or create credentials.\n\n" +
        "To obtain one:\n" +
        "1. Go to console.cloud.google.com and sign in with your Google account.\n" +
        "2. Create a project (or select an existing one).\n" +
        "3. Enable the Google Sheets API and Google Drive API for that project.\n" +
        "4. Go to IAM & Admin > Service Accounts and click Create Service Account.\n" +
        "5. Give it a name, click Done.\n" +
        "6. Click the service account, go to the Keys tab, and click Add Key > Create New Key.\n" +
        "7. Choose JSON and click Create - the file downloads automatically.\n" +
        "8. Open the file and copy the 'client_email', 'private_key', and 'project_id' values\n" +
        "   into the corresponding fields in Tools > Google Integration.";
}


// Returns help text explaining how to obtain OAuth2 Client ID and Client Secret from Google Cloud Console.
function GetOAuth2AppHelpText() {
    return "What are the OAuth2 App credentials?\n\n" +
        "An OAuth2 app lets individual users sign in with their own Google account so exports go directly\n" +
        "into their own Google Drive. The Client ID and Client Secret identify your application to Google,\n" +
        "and the Redirect URI tells Google where to send the user after they approve access.\n\n" +
        "Note: Google may require a billing account to activate a project, even for free-tier APIs.\n" +
        "The Google Sheets and Drive APIs do not charge for normal usage, but a credit card on file\n" +
        "may be required before Google will allow you to enable APIs or create credentials.\n\n" +
        "To obtain them:\n" +
        "1. Go to console.cloud.google.com and sign in with your Google account.\n" +
        "2. Create a project (or select an existing one).\n" +
        "3. Enable the Google Sheets API and Google Drive API for that project.\n" +
        "4. Go to APIs & Services > OAuth consent screen.\n" +
        "   - Choose 'External' (or 'Internal' if your org uses Google Workspace).\n" +
        "   - Fill in the app name and support email, then click Save and Continue.\n" +
        "   - Add the scopes: .../auth/spreadsheets and .../auth/drive.file, then finish.\n" +
        "5. Go to APIs & Services > Credentials and click Create Credentials > OAuth client ID.\n" +
        "6. Choose 'Web application' as the application type.\n" +
        "7. Under 'Authorized redirect URIs', add the Redirect URI shown in this dialog.\n" +
        "8. Click Create - Google shows your Client ID and Client Secret.\n" +
        "9. Copy those two values into the Client ID and Client Secret fields in this dialog.\n\n" +
        "Note: if your consent screen is set to 'Testing', only listed test users can connect.\n" +
        "Publish the app in the OAuth consent screen when you are ready for all users to connect.";
}


// Called by the OAuth popup via window.opener after GoogleOAuthCallback closes it.
// bSuccess is true when tokens were saved; false if the user cancelled or an error occurred.
function OnGoogleOAuthComplete(bSuccess) {
    console.log("GoogleOAuth callback: bSuccess=" + bSuccess);
    if (bSuccess) {
        ToastMessage("Google Sign-In", "Google account connected. You can now export to Google Sheets.");
        if ($("#igDialogGoogleAccount").is(":visible"))
            LoadGoogleAccountStatus();
    } else {
        PopupMessageBox("Google Sign-In Failed", GetOAuth2SignInFailedHelpText());
    }
}

// Returns help text explaining common causes of OAuth2 sign-in failure.
function GetOAuth2SignInFailedHelpText() {
    return "Google sign-in did not complete. Common causes:\n\n" +
        "1. Redirect URI not registered\n" +
        "   The Redirect URI shown in Tools > Google Integration must be added to your\n" +
        "   OAuth2 client in Google Cloud Console under Authorized redirect URIs.\n\n" +
        "2. Test user not listed\n" +
        "   If your OAuth consent screen is in Testing mode, only users listed under\n" +
        "   'Test users' in Google Cloud Console can sign in.\n\n" +
        "3. Consent screen not configured\n" +
        "   The OAuth consent screen must be saved with an app name and support email\n" +
        "   before any sign-in attempt will succeed.\n\n" +
        "4. Wrong OAuth client type\n" +
        "   The OAuth client in Google Cloud Console must be type 'Web application',\n" +
        "   not Desktop or Android.\n\n" +
        "5. User cancelled\n" +
        "   If you closed the popup or clicked Deny, try again and click Allow.";
}


// Google Sheets Import

// Called from File > Import > Google Sheets.
function OnImportFromGoogleSheets() {
    OpenGoogleImportDialog();
}

// Opens the Import from Google Sheets dialog. Steps:
// 1. Size the igDialog to fit the viewport (capped at 600px wide).
// 2. Pre-fill the URL field from localStorage ("st-google-import-url"); blank if never saved.
// 3. Reset the tab dropdown and hide the SA share note and status bar.
// 4. Open the dialog and focus the URL field.
// 5. Wire button/keyboard handlers (unbind first to prevent duplicate handlers on re-open).
// 6. If a saved URL was restored, auto-click Load so the tab dropdown is ready immediately.
function OpenGoogleImportDialog() {
    // 1. Size
    var nDlgWidth = Math.min(600, $(window).width() - 40);

    $("#igDialogGoogleImport").igDialog({
        modal: true, headerText: "Import from Google Sheets", width: nDlgWidth, height: 420,
        resizable: false, closeOnEscape: true, openAnimation: "", closeAnimation: "fade"
    });

    // 2. Restore last-used URL; 3. Reset tab dropdown and auxiliary UI
    $("#GoogleImportUrl").val(localStorage.getItem("st-google-import-url") || "");
    $("#GoogleImportTab").html('<option value="">-- enter URL above and click Load --</option>');
    $("#GoogleImportSaNote").hide();
    $("#GoogleImportStatusDiv").hide();

    // 4. Open and focus
    $("#igDialogGoogleImport").igDialog("open");
    $("#GoogleImportUrl").focus();

    // 5. Wire handlers
    $("#GoogleImportLoadTabsButton").unbind().click(function () { OnGoogleImportLoadTabs(); });
    $("#GoogleImportButton").unbind().click(function () { OnGoogleImportDialogImport(); });
    $("#GoogleImportCancelButton").unbind().click(function () { CloseGoogleImportDialog(); });
    $("#GoogleImportUrl").off("keydown").on("keydown", function (e) {
        if (e.which === 13) { OnGoogleImportLoadTabs(); }
    });

    // 6. Auto-load tabs if a URL was restored
    if ($("#GoogleImportUrl").val()) { $("#GoogleImportLoadTabsButton").click(); }
}

function CloseGoogleImportDialog() {
    $("#igDialogGoogleImport").igDialog("close");
}

// Calls AjaxGetGoogleSheetTabs with the pasted URL; populates the tab dropdown on success.
function OnGoogleImportLoadTabs() {
    var sUrl = $("#GoogleImportUrl").val().trim();
    if (!sUrl) { ToastError("Google Import", "Enter a Google Sheets URL or spreadsheet ID."); return; }

    $("#GoogleImportLoadTabsButton").prop("disabled", true).val("...");
    $("#GoogleImportSaNote").hide();
    ShowGoogleImportStatus("Loading tabs...");

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetGoogleSheetTabs",
        type: "POST",
        data: JSON.stringify({ sSpreadsheetUrl: sUrl }),
        contentType: "application/json",
        success: function (response) {
            $("#GoogleImportLoadTabsButton").prop("disabled", false).val("Load");
            if (!response.Success) {
                console.error("GoogleImportLoadTabs failed: " + response.ErrorResults);
                HideGoogleImportStatus();
                ToastError("Google Import", response.ErrorResults);
                return;
            }
            var tabs = response.Tabs || [];
            var sOptions = "";
            for (var i = 0; i < tabs.length; i++)
                sOptions += '<option value="' + tabs[i].replace(/"/g, "&quot;") + '">' + tabs[i] + '</option>';
            $("#GoogleImportTab").html(sOptions);

            try { localStorage.setItem("st-google-import-url", sUrl); } catch (e) { }

            // Show service account share note if the server fell back to SA credentials
            if (response.SaEmail) {
                $("#GoogleImportSaEmail").text(response.SaEmail);
                $("#GoogleImportSaNote").show();
            }
            HideGoogleImportStatus();
        },
        error: function (xhr) {
            $("#GoogleImportLoadTabsButton").prop("disabled", false).val("Load");
            HideGoogleImportStatus();
            console.error("GoogleImportLoadTabs HTTP error: " + xhr.status + " " + xhr.statusText);
            ToastError("Google Import", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}

function OnGoogleImportDialogImport() {
    var sUrl        = $("#GoogleImportUrl").val().trim();
    var sTab        = $("#GoogleImportTab").val();
    var sRecordType = $("#GoogleImportRecordType").val();

    if (!sUrl) { ToastError("Google Import", "Enter a Google Sheets URL or spreadsheet ID."); return; }
    if (!sTab) { ToastError("Google Import", "Select a sheet tab."); return; }

    CloseGoogleImportDialog();
    DoGoogleSheetsImport(sUrl, sTab, sRecordType);
}

// Sends the import request. sSpreadsheetUrl may be a full URL or bare ID.
function DoGoogleSheetsImport(sSpreadsheetUrl, sSheetName, sRecordType) {
    OpenPleaseWaitDialog("Import");

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxImportFromGoogleSheets",
        type: "POST",
        data: JSON.stringify({
            sSpreadsheetUrl: sSpreadsheetUrl,
            sSheetName: sSheetName,
            sRecordType: sRecordType
        }),
        contentType: "application/json",
        success: function (response) {
            ClosePleaseWaitDialog();
            if (response.Success) {
                console.log("GoogleSheets import succeeded: " + response.ImportResults);
                RefreshSelectedContent();
                ToastMessage("Import", response.ImportResults || "Google Sheets import complete.");
            } else {
                console.error("GoogleSheets import failed: " + response.ErrorResults);
                ToastError("Import from Google Sheets", response.ErrorResults);
            }
        },
        error: function (xhr) {
            ClosePleaseWaitDialog();
            console.error("GoogleSheets import HTTP error: " + xhr.status + " " + xhr.statusText);
            ToastError("Import from Google Sheets", "Error " + xhr.status + ", " + xhr.statusText);
        }
    });
}

function ShowGoogleImportStatus(sMessage) {
    $("#GoogleImportStatusLabel").text(sMessage);
    $("#GoogleImportStatusDiv").show();
}

function HideGoogleImportStatus() {
    $("#GoogleImportStatusDiv").hide();
}
