<?php
require_once 'config.php'; // Includes session_start() and defines DATA_DIR

use QuickBooksOnline\API\DataService\DataService;
use QuickBooksOnline\API\Core\OAuth2\OAuth2LoginHelper;
use QuickBooksOnline\API\Exception\ServiceException;

// --- Authentication Check and Token Refresh (Keep previous logic) ---
if (!isset($_SESSION['accessTokenKey']) || !isset($_SESSION['refreshTokenKey']) || !isset($_SESSION['realmId'])) {
    $_SESSION['error'] = "Not authenticated. Please connect to QuickBooks first.";
    logError("Consolidated Download: Attempt without authentication.");
    header('Location: index.php');
    exit;
}

$accessTokenKey = $_SESSION['accessTokenKey'];
$refreshTokenKey = $_SESSION['refreshTokenKey'];
$realmId = $_SESSION['realmId'];
$tokenExpiresAtStr = $_SESSION['tokenExpiresAt'] ?? null;

$isExpired = true; // Assume expired
if ($tokenExpiresAtStr) {
    try {
        $expiryTimestamp = strtotime($tokenExpiresAtStr);
        if ($expiryTimestamp !== false) {
            $isExpired = ($expiryTimestamp - (5 * 60)) < time(); // Check if expiring within 5 mins
        } else { logError("Consolidated Download: Failed to parse token expiry time string", $tokenExpiresAtStr); }
    } catch (Exception $e) { logError("Consolidated Download: Error parsing token expiry time", ['string' => $tokenExpiresAtStr, 'error' => $e->getMessage()]); }
}

$dataService = null; // Initialize

if ($isExpired) {
    logError("Consolidated Download: Token expired or nearing expiry. Attempting refresh.", ['realmId' => $realmId]);
    try {
        $dataServiceForRefresh = DataService::Configure([ /* ... refresh config ... */
             'auth_mode' => 'oauth2', 'ClientID' => $clientID, 'ClientSecret' => $clientSecret,
             'RedirectURI' => $redirectURI, 'scope' => $scope, 'baseUrl' => $baseURL,
             'refreshTokenKey' => $refreshTokenKey ]);
        $oauth2LoginHelper = $dataServiceForRefresh->getOAuth2LoginHelper();
        $refreshedAccessToken = $oauth2LoginHelper->refreshToken();

        // Configure the final $dataService instance
        $dataService = DataService::Configure([ /* ... final config ... */
            'auth_mode' => 'oauth2', 'ClientID' => $clientID, 'ClientSecret' => $clientSecret,
            'scope' => $scope, 'baseUrl' => $baseURL,
            'accessTokenKey' => $refreshedAccessToken->getAccessToken(),
            'refreshTokenKey' => $refreshedAccessToken->getRefreshToken(),
            'QBORealmID' => $realmId,
             'minorVersion' => '70' // Keep minor version if it helped before, or remove if not needed
        ]);
        $dataService->throwExceptionOnError(true); // Throw exceptions on SDK errors

        // Update session
        $_SESSION['accessTokenKey'] = $refreshedAccessToken->getAccessToken();
        $_SESSION['refreshTokenKey'] = $refreshedAccessToken->getRefreshToken();
        $_SESSION['tokenExpiresAt'] = $refreshedAccessToken->getAccessTokenExpiresAt();
        logError("Consolidated Download: Token refreshed & DataService configured.", ['realmId' => $realmId]);

    } catch (Exception $e) { /* ... handle refresh failure ... */
        logError("Consolidated Download: Failed to refresh token", ['error' => $e->getMessage(), 'realmId' => $realmId]);
        session_unset(); session_destroy(); session_start();
        $_SESSION['error'] = "Failed to refresh QuickBooks connection: " . $e->getMessage() . ". Please connect again.";
        header('Location: index.php');
        exit;
    }
}

// --- Configure DataService if Token Was NOT Refreshed ---
try {
    if ($dataService === null) {
        logError("Consolidated Download: Token not expired. Configuring DataService.", ['realmId' => $realmId]);
        $dataService = DataService::Configure([ /* ... standard config ... */
            'auth_mode' => 'oauth2', 'ClientID' => $clientID, 'ClientSecret' => $clientSecret,
            'scope' => $scope, 'baseUrl' => $baseURL,
            'accessTokenKey' => $accessTokenKey, 'refreshTokenKey' => $refreshTokenKey,
            'QBORealmID' => $realmId,
            'minorVersion' => '70' // Keep minor version
        ]);
        if (!$dataService instanceof DataService) { throw new \Exception("DataService::Configure did not return a valid object."); }
        $dataService->throwExceptionOnError(true);
        logError("Consolidated Download: DataService configured successfully.", ['realmId' => $realmId]);
    }
} catch (\Throwable $e) { /* ... handle configuration failure ... */
     logError("Consolidated Download: CRITICAL - Failed during DataService::Configure", [ /*...*/ ]);
     $_SESSION['error'] = "Failed to initialize QuickBooks connection: " . $e->getMessage();
     header('Location: index.php');
     exit;
}

// --- Data Fetching Logic ---
$downloadStatus = [
    'Accounts' => ['success' => false, 'count' => 0, 'error' => null],
    'PrevMonthExpenses' => ['success' => false, 'count' => 0, 'error' => null, 'period' => 'N/A'],
    'PrevMonthSales'    => ['success' => false, 'count' => 0, 'error' => null, 'period' => 'N/A'],
    'PrevMonthNewCustomers' => ['success' => false, 'count' => 0, 'error' => null, 'period' => 'N/A'],
    'CurrentMonthTransactions' => ['success' => false, 'count' => 0, 'error' => null, 'period' => 'N/A'],
    'ProfitAndLossReport' => ['success' => false, 'count' => null, 'error' => null, 'period' => 'N/A'], // Added
];
$overallErrorMessages = [];

try {
    // Ensure $dataService is valid
    if (!isset($dataService) || !$dataService instanceof DataService) {
        throw new \Exception("DataService object is invalid before fetching data.");
    }
    logError("Consolidated Download: Starting data fetch.", ['realmId' => $realmId]);

    // --- 1. Fetch Accounts ---
    try {
        logError("Consolidated Download: Fetching Accounts...", ['realmId' => $realmId]);
        // Note: Increase MAXRESULTS if you have more than 1000 accounts. Pagination needed for > 1000.
        $accounts = $dataService->Query("SELECT * FROM Account MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching Accounts: " . $error->getResponseBody()); }
        if ($accounts === null) { $accounts = []; } // Handle null response

        $accountsData = [];
        foreach ($accounts as $account) {
            $accountsData[] = [ /* ... format account data as before ... */
                'id' => $account->Id, 'name' => $account->Name, 'type' => $account->AccountType,
                'subtype' => $account->AccountSubType ?? '', 'current_balance' => property_exists($account, 'CurrentBalance') ? (float)$account->CurrentBalance : 0.0,
                'active' => (bool)$account->Active, 'classification' => $account->Classification ?? '',
                'currency_ref' => $account->CurrencyRef ?? '', 'account_number' => $account->AcctNum ?? '' ];
        }

        $jsonData = json_encode($accountsData, JSON_PRETTY_PRINT);
        if ($jsonData === false || file_put_contents(ACCOUNTS_FILE, $jsonData) === false) {
            throw new \Exception("Failed to save Accounts data to " . ACCOUNTS_FILE);
        }
        $downloadStatus['Accounts']['success'] = true;
        $downloadStatus['Accounts']['count'] = count($accountsData);
        logError("Consolidated Download: Accounts fetch successful.", ['count' => count($accountsData), 'file' => ACCOUNTS_FILE]);

    } catch (\Throwable $e) {
        $downloadStatus['Accounts']['error'] = $e->getMessage();
        $overallErrorMessages[] = "Accounts: " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving Accounts.", ['error' => $e->getMessage()]);
    }


    // --- Calculate Date Range for Previous Month ---
    $prevMonthTimestamp = strtotime('first day of last month');
    $startDate = date('Y-m-d', $prevMonthTimestamp);
    $endDate = date('Y-m-t', $prevMonthTimestamp); // 't' gives last day of the month
    $fileSuffix = date('Y-m', $prevMonthTimestamp);
    $periodDesc = date('F Y', $prevMonthTimestamp);

    $downloadStatus['Expenses']['period'] = $periodDesc;
    $downloadStatus['Sales']['period'] = $periodDesc;
    $downloadStatus['NewCustomers']['period'] = $periodDesc;


    // --- 2. Fetch Expenses (Purchases, Bills, VendorCredits) for Previous Month ---
    try {
        logError("Consolidated Download: Fetching Expenses for {$periodDesc}...", ['realmId' => $realmId, 'start' => $startDate, 'end' => $endDate]);
        $allExpenses = [];

        // Fetch Purchases
        $purchases = $dataService->Query("SELECT * FROM Purchase WHERE TxnDate >= '{$startDate}' AND TxnDate <= '{$endDate}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching Purchases: " . $error->getResponseBody()); }
        if ($purchases) { $allExpenses = array_merge($allExpenses, $purchases); }

        // Fetch Bills
        $bills = $dataService->Query("SELECT * FROM Bill WHERE TxnDate >= '{$startDate}' AND TxnDate <= '{$endDate}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching Bills: " . $error->getResponseBody()); }
        if ($bills) { $allExpenses = array_merge($allExpenses, $bills); }

        // Fetch VendorCredits
        $vendorCredits = $dataService->Query("SELECT * FROM VendorCredit WHERE TxnDate >= '{$startDate}' AND TxnDate <= '{$endDate}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching VendorCredits: " . $error->getResponseBody()); }
        if ($vendorCredits) { $allExpenses = array_merge($allExpenses, $vendorCredits); } // Note: You'll need to handle credits vs debits in analysis

        $expensesFile = DATA_DIR . '/expenses_' . $fileSuffix . '.json';
        $jsonData = json_encode($allExpenses, JSON_PRETTY_PRINT);
        if ($jsonData === false || file_put_contents($expensesFile, $jsonData) === false) {
            throw new \Exception("Failed to save Expenses data to " . $expensesFile);
        }
        $downloadStatus['Expenses']['success'] = true;
        $downloadStatus['Expenses']['count'] = count($allExpenses);
        logError("Consolidated Download: Expenses fetch successful.", ['count' => count($allExpenses), 'file' => $expensesFile]);

    } catch (\Throwable $e) {
        $downloadStatus['Expenses']['error'] = $e->getMessage();
        $overallErrorMessages[] = "Expenses ({$periodDesc}): " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving Expenses.", ['error' => $e->getMessage(), 'period' => $periodDesc]);
    }

    // --- 3. Fetch Sales (Invoices, SalesReceipts) for Previous Month ---
     try {
        logError("Consolidated Download: Fetching Sales for {$periodDesc}...", ['realmId' => $realmId, 'start' => $startDate, 'end' => $endDate]);
        $allSales = [];

        // Fetch Invoices
        $invoices = $dataService->Query("SELECT * FROM Invoice WHERE TxnDate >= '{$startDate}' AND TxnDate <= '{$endDate}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching Invoices: " . $error->getResponseBody()); }
        if ($invoices) { $allSales = array_merge($allSales, $invoices); }

        // Fetch SalesReceipts
        $salesReceipts = $dataService->Query("SELECT * FROM SalesReceipt WHERE TxnDate >= '{$startDate}' AND TxnDate <= '{$endDate}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching SalesReceipts: " . $error->getResponseBody()); }
        if ($salesReceipts) { $allSales = array_merge($allSales, $salesReceipts); }

        $salesFile = DATA_DIR . '/sales_' . $fileSuffix . '.json';
        $jsonData = json_encode($allSales, JSON_PRETTY_PRINT);
        if ($jsonData === false || file_put_contents($salesFile, $jsonData) === false) {
            throw new \Exception("Failed to save Sales data to " . $salesFile);
        }
        $downloadStatus['Sales']['success'] = true;
        $downloadStatus['Sales']['count'] = count($allSales);
        logError("Consolidated Download: Sales fetch successful.", ['count' => count($allSales), 'file' => $salesFile]);

    } catch (\Throwable $e) {
        $downloadStatus['Sales']['error'] = $e->getMessage();
        $overallErrorMessages[] = "Sales ({$periodDesc}): " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving Sales.", ['error' => $e->getMessage(), 'period' => $periodDesc]);
    }

    // --- 4. Fetch New Customers Created Previous Month ---
    try {
        logError("Consolidated Download: Fetching New Customers for {$periodDesc}...", ['realmId' => $realmId, 'start' => $startDate, 'end' => $endDate]);
        // Adjust dates to include full timestamp for MetaData query
        $startDateTime = $startDate . 'T00:00:00Z'; // Use ISO 8601 Format with UTC (Z)
        $endDateTime = $endDate . 'T23:59:59Z';

        $newCustomers = $dataService->Query("SELECT Id, MetaData.CreateTime, DisplayName FROM Customer WHERE MetaData.CreateTime >= '{$startDateTime}' AND MetaData.CreateTime <= '{$endDateTime}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) { throw new ServiceException("API Error fetching New Customers: " . $error->getResponseBody()); }
        if ($newCustomers === null) { $newCustomers = []; }

        $newCustomersFile = DATA_DIR . '/new_customers_' . $fileSuffix . '.json';
        $jsonData = json_encode($newCustomers, JSON_PRETTY_PRINT);
        if ($jsonData === false || file_put_contents($newCustomersFile, $jsonData) === false) {
            throw new \Exception("Failed to save New Customers data to " . $newCustomersFile);
        }
        $downloadStatus['NewCustomers']['success'] = true;
        $downloadStatus['NewCustomers']['count'] = count($newCustomers);
        logError("Consolidated Download: New Customers fetch successful.", ['count' => count($newCustomers), 'file' => $newCustomersFile]);

    } catch (\Throwable $e) {
        $downloadStatus['NewCustomers']['error'] = $e->getMessage();
        $overallErrorMessages[] = "New Customers ({$periodDesc}): " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving New Customers.", ['error' => $e->getMessage(), 'period' => $periodDesc]);
    }
    // --- 5. Fetch Current Month Transactions ---
try {
    logError("Consolidated Download: Fetching Current Month Transactions...", ['realmId' => $realmId]);
    $currentMonthStart = date('Y-m-01');
    $currentMonthEnd   = date('Y-m-t'); // Last day of the current month
    $currentTransactions = $dataService->Query("SELECT * FROM Transaction WHERE TxnDate >= '{$currentMonthStart}' AND TxnDate <= '{$currentMonthEnd}' MAXRESULTS 1000");
    $error = $dataService->getLastError();
    if ($error) {
        throw new ServiceException("API Error fetching Current Month Transactions: " . $error->getResponseBody());
    }
    $currentTransFile = DATA_DIR . '/transactions_current_' . date('Y-m') . '.json';
    $jsonData = json_encode($currentTransactions, JSON_PRETTY_PRINT);
    if ($jsonData === false || file_put_contents($currentTransFile, $jsonData) === false) {
        throw new \Exception("Failed to save Current Month Transactions data to " . $currentTransFile);
    }
    $downloadStatus['CurrentMonthTransactions']['success'] = true;
    $downloadStatus['CurrentMonthTransactions']['count'] = count($currentTransactions);
    logError("Consolidated Download: Current Month Transactions fetch successful.", ['count' => count($currentTransactions), 'file' => $currentTransFile]);
} catch (\Throwable $e) {
    // If today is the 1st of the month, ignore the error (just log a warning)
    if (date('j') == 1) {
        logError("Consolidated Download: Ignoring error for current month transactions on the 1st of the month.", ['error' => $e->getMessage()]);
        $downloadStatus['CurrentMonthTransactions']['success'] = true;
        $downloadStatus['CurrentMonthTransactions']['count'] = 0;
    } else {
        $downloadStatus['CurrentMonthTransactions']['error'] = $e->getMessage();
        $overallErrorMessages[] = "Current Month Transactions: " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving Current Month Transactions.", ['error' => $e->getMessage()]);
    }
}

    // --- 6. Fetch Last Month Transactions ---
    try {
        logError("Consolidated Download: Fetching Last Month Transactions...", ['realmId' => $realmId]);
        $lastMonthStart = date('Y-m-01', strtotime('first day of last month'));
        $lastMonthEnd   = date('Y-m-t', strtotime('first day of last month'));
        $lastMonthTransactions = $dataService->Query("SELECT * FROM Transaction WHERE TxnDate >= '{$lastMonthStart}' AND TxnDate <= '{$lastMonthEnd}' MAXRESULTS 1000");
        $error = $dataService->getLastError();
        if ($error) {
            throw new ServiceException("API Error fetching Last Month Transactions: " . $error->getResponseBody());
        }
        $lastTransFile = DATA_DIR . '/transactions_last_' . date('Y-m', strtotime('first day of last month')) . '.json';
        $jsonData = json_encode($lastMonthTransactions, JSON_PRETTY_PRINT);
        if ($jsonData === false || file_put_contents($lastTransFile, $jsonData) === false) {
            throw new \Exception("Failed to save Last Month Transactions data to " . $lastTransFile);
        }
        $downloadStatus['LastMonthTransactions'] = [
            'success' => true,
            'count'   => count($lastMonthTransactions),
            'error'   => null,
            'period'  => date('F Y', strtotime('first day of last month'))
        ];
        logError("Consolidated Download: Last Month Transactions fetch successful.", ['count' => count($lastMonthTransactions), 'file' => $lastTransFile]);
    } catch (\Throwable $e) {
        $downloadStatus['LastMonthTransactions'] = [
            'success' => false,
            'count'   => 0,
            'error'   => $e->getMessage(),
            'period'  => date('F Y', strtotime('first day of last month'))
        ];
        $overallErrorMessages[] = "Last Month Transactions: " . $e->getMessage();
        logError("Consolidated Download: ERROR fetching/saving Last Month Transactions.", ['error' => $e->getMessage()]);
    }


    // --- Generate Final Session Messages ---
    $successMessages = [];
    $failureMessages = [];
    foreach ($downloadStatus as $type => $status) {
        $periodInfo = isset($status['period']) && $status['period'] !== 'N/A' ? " ({$status['period']})" : "";
        if ($status['success']) {
            $successMessages[] = "{$type}{$periodInfo}: OK ({$status['count']} records)";
        } else {
            $failureMessages[] = "{$type}{$periodInfo}: FAILED";
        }
    }

    if (empty($overallErrorMessages)) {
        $_SESSION['message'] = "Data refresh completed successfully. " . implode(', ', $successMessages) . ".";
    } else {
        $_SESSION['message'] = "Data refresh completed with errors. Success: [" . implode(', ', $successMessages) . "]. Failures: [" . implode(', ', $failureMessages) . "].";
        $_SESSION['error'] = "Errors occurred during data refresh: " . implode('; ', $overallErrorMessages);
    }


} catch (\Throwable $e) { // Catch errors during DataService usage if throwExceptionOnError is off, or other major issues
    logError("Consolidated Download: Uncaught Exception during data fetch.", [
        'error_class' => get_class($e), 'error_message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
    $_SESSION['error'] = "A critical error occurred during data download: " . $e->getMessage();
}

// Redirect back to index.php
header('Location: index.php');
exit;
?>