# Google Business Profile (GBP) Integration Guide

## Overview
This guide explains how to integrate Google Business Profile OAuth flow with location selection and plan assignment.

## Flow Summary

1. **User initiates OAuth** → Frontend sends request to `/api/gbp/oauth/initiate`
2. **Backend generates auth URL** → Returns Google OAuth URL
3. **User authorizes** → Google redirects to `/api/gbp/oauth/callback`
4. **Backend receives tokens** → Saves tokens and fetches all GBP locations
5. **User chooses location** → Frontend displays locations, user selects one
6. **Backend saves location** → Assigns free plan and stores location data
7. **User can upgrade** → View plans ($197, $997) and upgrade

## API Endpoints

### 1. Initiate OAuth Flow

**POST** `/api/gbp/oauth/initiate`

**Headers:**
```
Authorization: Bearer <JWT_TOKEN>
```

**Request Body:**
```json
{
  "account_id": "1",
  "redirect_uri": "http://localhost:5173/setup/gbp/callback"
}
```

**Response:**
```json
{
  "success": true,
  "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "message": "Redirect user to auth_url to begin OAuth flow"
}
```

**Frontend Usage:**
```javascript
// Step 1: Initiate OAuth
const response = await fetch('http://localhost:5000/api/gbp/oauth/initiate', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({
    account_id: "1",
    redirect_uri: "http://localhost:5173/setup/gbp/callback"
  })
});

const data = await response.json();

// Step 2: Redirect user to Google OAuth
window.location.href = data.auth_url;
```

---

### 2. OAuth Callback (Handled by Backend)

**GET** `/api/gbp/oauth/callback`

**Query Parameters:**
- `code`: Authorization code from Google
- `state`: JSON string containing `{ account_id, redirect_uri }`

**Flow:**
1. Backend exchanges code for tokens
2. Saves tokens to account
3. Fetches all GBP locations
4. Redirects to frontend: `{redirect_uri}?success=true`

**Frontend Callback Page:**
```javascript
// On http://localhost:5173/setup/gbp/callback
const urlParams = new URLSearchParams(window.location.search);
const success = urlParams.get('success');
const error = urlParams.get('error');

if (success) {
  // OAuth successful, now fetch locations
  fetchGBPLocations();
} else if (error) {
  // Handle error
  console.error('OAuth error:', error);
}
```

---

### 3. Get GBP Locations

**GET** `/api/gbp/locations`

**Headers:**
```
Authorization: Bearer <JWT_TOKEN>
```

**Response:**
```json
{
  "success": true,
  "count": 3,
  "locations": [
    {
      "accountResourceName": "accounts/123456789",
      "name": "My Business Name",
      "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
      "address": {
        "regionCode": "US",
        "locality": "San Francisco",
        "administrativeArea": "CA",
        "postalCode": "94102",
        "addressLines": ["123 Main St"]
      },
      "phoneNumbers": {
        "primaryPhone": "+1-415-555-0123"
      },
      "websiteUri": "https://example.com",
      "latlng": {
        "latitude": 37.7749,
        "longitude": -122.4194
      },
      "locationKey": "locations/987654321",
      "raw": { /* full GBP location object */ }
    }
  ]
}
```

**Frontend Usage:**
```javascript
const response = await fetch('http://localhost:5000/api/gbp/locations', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const data = await response.json();

// Display locations as radio buttons
data.locations.forEach(location => {
  // Render location option
  console.log(location.name, location.address);
});
```

---

### 4. Select Location

**POST** `/api/gbp/locations/select`

**Headers:**
```
Authorization: Bearer <JWT_TOKEN>
```

**Request Body:**
```json
{
  "location_data": {
    "name": "My Business Name",
    "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "address": {
      "regionCode": "US",
      "locality": "San Francisco",
      "administrativeArea": "CA",
      "postalCode": "94102"
    },
    "phoneNumbers": {
      "primaryPhone": "+1-415-555-0123"
    },
    "websiteUri": "https://example.com",
    "latlng": {
      "latitude": 37.7749,
      "longitude": -122.4194
    },
    "locationKey": "locations/987654321"
  }
}
```

**Response:**
```json
{
  "success": true,
  "location": {
    "id": 1,
    "client_id": 1,
    "name": "My Business Name",
    "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94102",
    "country": "US",
    "phone": "+1-415-555-0123",
    "website_url": "https://example.com",
    "lat": 37.7749,
    "lng": -122.4194,
    "gbp_connected": true,
    "plan_id": 1,
    "price_per_month": 0,
    "onboarding_status": "in_progress",
    "seo_status": "free"
  },
  "plan": {
    "id": 1,
    "plan_code": "free-plan",
    "display_name": "Free Plan",
    "description": "Free tier with basic features",
    "price_per_month": 0
  },
  "message": "Location saved and free plan assigned"
}
```

**Frontend Usage:**
```javascript
const selectedLocation = locations[selectedIndex];

const response = await fetch('http://localhost:5000/api/gbp/locations/select', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({
    location_data: selectedLocation
  })
});

const data = await response.json();

// Location saved with free plan
console.log('Location saved:', data.location);
console.log('Assigned plan:', data.plan);

// Now show upgrade options
showPlanUpgradeOptions();
```

---

## Plans

The system includes three plans:

1. **Free Plan** - $0/month
   - Basic features
   - Automatically assigned when location is selected

2. **Starter Plan** - $197/month
   - Perfect for small businesses
   - Enhanced local SEO features

3. **Pro Plan** - $997/month
   - Advanced features
   - Full local search domination toolkit

### Seeding Plans

Run the seed script to create/update plans:

```bash
node prisma/seed-plans.js
```

---

## Database Schema

### Location Fields (GBP-related)

```prisma
model Location {
  id                  Int     @id @default(autoincrement())
  client_id           Int
  
  name                String?
  place_id            String?
  gbp_location_key    String?    // GBP resource name for API updates
  
  full_address        String?
  city                String?
  state               String?
  zip                 String?
  country             String?
  phone               String?
  
  website_url         String?
  has_website         Boolean    @default(false)
  
  lat                 Float?
  lng                 Float?
  
  gbp_connected       Boolean    @default(false)
  
  plan_id             Int?
  price_per_month     Decimal?
  
  onboarding_status   OnboardingStatus @default(not_started)
  seo_status          SEOStatus        @default(prospect)
}
```

### Account Fields (OAuth tokens)

```prisma
model Account {
  google_access_token  String?
  google_refresh_token String?
  google_token_expiry  DateTime?
}
```

---

## Frontend Implementation Example

### Complete Flow

```javascript
// 1. Initiate OAuth
async function startGBPSetup() {
  const response = await fetch('http://localhost:5000/api/gbp/oauth/initiate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${getToken()}`
    },
    body: JSON.stringify({
      account_id: getCurrentAccountId(),
      redirect_uri: 'http://localhost:5173/setup/gbp/callback'
    })
  });
  
  const data = await response.json();
  window.location.href = data.auth_url;
}

// 2. Handle callback
// On /setup/gbp/callback page
async function handleOAuthCallback() {
  const params = new URLSearchParams(window.location.search);
  
  if (params.get('success')) {
    // Fetch locations
    const locations = await fetchGBPLocations();
    displayLocationSelection(locations);
  } else {
    showError(params.get('error'));
  }
}

// 3. Fetch locations
async function fetchGBPLocations() {
  const response = await fetch('http://localhost:5000/api/gbp/locations', {
    headers: {
      'Authorization': `Bearer ${getToken()}`
    }
  });
  
  const data = await response.json();
  return data.locations;
}

// 4. Select location
async function selectLocation(locationData) {
  const response = await fetch('http://localhost:5000/api/gbp/locations/select', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${getToken()}`
    },
    body: JSON.stringify({
      location_data: locationData
    })
  });
  
  const data = await response.json();
  
  // Show success and plan upgrade options
  showSuccessMessage('Location connected!');
  showPlanUpgradeOptions([
    { name: 'Starter Plan', price: 197 },
    { name: 'Pro Plan', price: 997 }
  ]);
}
```

---

## Environment Variables

Required in `.env`:

```env
# Google OAuth (GBP)
GOOGLE_CLIENT_ID=205506700327-dgkcnndfq9ipg887g763n59kuk8m5s3e.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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
GOOGLE_REDIRECT_URI=http://localhost:5000/api/gbp/oauth/callback

# Frontend
FRONTEND_URL=http://localhost:5173
```

---

## Testing

### Manual Testing Steps

1. **Start the backend:**
   ```bash
   npm run dev
   ```

2. **Test OAuth initiation:**
   ```bash
   curl -X POST http://localhost:5000/api/gbp/oauth/initiate \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -d '{"account_id":"1","redirect_uri":"http://localhost:5173/setup/gbp/callback"}'
   ```

3. **Visit the auth_url** returned in the response

4. **After OAuth callback, fetch locations:**
   ```bash
   curl http://localhost:5000/api/gbp/locations \
     -H "Authorization: Bearer YOUR_JWT_TOKEN"
   ```

5. **Select a location:**
   ```bash
   curl -X POST http://localhost:5000/api/gbp/locations/select \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -d '{"location_data":{...}}'
   ```

---

## Future Enhancements

1. **Location Updates Sync to GBP**
   - Implement `updateLocationAndSyncToGBP` in `gbp.service.js`
   - Use Google My Business API to push changes back to GBP

2. **Multiple Locations**
   - Allow users to connect multiple GBP locations
   - Manage separate plans for each location

3. **Plan Upgrades**
   - Implement Stripe integration for plan upgrades
   - Handle subscription management

4. **Webhook Support**
   - Listen for GBP changes via webhooks
   - Auto-sync location updates

---

## Troubleshooting

### OAuth Errors

- **"redirect_uri_mismatch"**: Ensure `GOOGLE_REDIRECT_URI` in `.env` matches the one configured in Google Cloud Console
- **"invalid_grant"**: Token expired, user needs to re-authorize

### Location Not Found

- Ensure user has access to GBP locations
- Check that OAuth scopes include `business.manage`

### Database Errors

- Run migrations: `npx prisma db push --accept-data-loss`
- Seed plans: `node prisma/seed-plans.js`
- Add missing column: Run SQL in `prisma/migrations/add_gbp_location_key.sql`

---

## Support

For issues or questions, refer to:
- [Google My Business API Documentation](https://developers.google.com/my-business)
- [Prisma Documentation](https://www.prisma.io/docs)
