// Version: 1.0.0 import 'package:flutter/foundation.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:googleapis_auth/google_auth.dart'; import 'package:googleapis/gmail/v1.dart'; /// Gmail API を介した同期用メールリレー(複数アカウント対応) /// /// P2P 通信不要なノード識別システムを提供します。 /// BCC の Gmail アドレスをノードの一意キーとして使用。 class GmailWrapper { final String _gmailAddress; // BCC 用 gmail アドレス(ノードキー) GAuthClient? _authClient; // OAuth 認証クライアント final GmailService? _gmail; // Gmail API サービス final GoogleSignIn _signIn; // GoogleSignIn インスタンス /// 新しいインスタンスを作成 factory GmailWrapper({ required String gmailAddress, bool useOAuth = true, }) { if (useOAuth) { print('[Gmail] OAuth 認証モード。GoogleSignIn でアカウント選択を行います'); final signIn = GoogleSignIn( scopes: [ 'https://www.googleapis.com/auth/gmail.readonly', 'https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/drive.readonly', 'https://www.googleapis.com/auth/spreadsheets.readonly', ], ); return GmailWrapper._internal( gmailAddress: gmailAddress, signIn: signIn, ); } else { throw UnsupportedError('OAuth 方式でのみサポートされています'); } } GmailWrapper._internal({ required this._gmailAddress, required GoogleSignIn signIn, }) : _signIn = signIn, _authClient = null, _gmail = null; /// ノード ID(BCC アドレス)を取得 String get gmailAddress => _gmailAddress; /// 認証状態を確認 bool get isAuthorized => _gmail != null; /// GoogleSignIn インスタンスを取得 GoogleSignIn get signInInstance => _signIn; /// 現在選択中のアカウントのメールアドレスを取得 String? get currentAccountEmail => _signIn.currentUser?.email; /// 認証された Google アカウント情報を取得(初回実行時は null) GoogleSignInAccount? get currentUser => _signIn.currentUser; /// チャットメッセージをノードに配送する Future sendMessage({ required String fromNode, required String message, String? toNode, }) async { if (_gmail == null) return; try { final msg = EmailMessage( subject: '[SalesAssist1] チャット:$fromNode', to: toNode, cc: null, bcc: _gmailAddress, // BCC でノード識別 htmlBody: '

$message

', ); final response = await _gmail.users.messages.send( userId: 'me', body: msg, ).root; print('[Gmail] メッセージ送信完了 (from=$fromNode to=${toNode ?? 'BCC キー'})'); } catch (e) { print('[Gmail] 送信失敗:$e'); rethrow; } } /// ノードリストを取得(自己認識用) Future> getNodes() async { // 現在接続可能なノードを返す(ハートビートの結果などから集約) return []; // ここに母艦が管理するノードリストを読み込むロジック } /// OAuth 認証フローを実行(初回またはアカウント切り替え時) Future authenticate() async { try { final account = await _signIn.signIn(); if (account != null) { print('[Gmail] 認証成功:${account.email}'); return account; } else { throw Exception('ユーザーが認証をキャンセルしました'); } } catch (e) { print('[Gmail] 認証失敗:$e'); rethrow; } } /// 現在のアカウントでログアウト Future logout() async { try { await _signIn.signOut(); print('[Gmail] ログアウト済み'); } catch (e) { print('[Gmail] ログアウト失敗:$e'); } } /// アカウント切り替え(複数アカウントを持つ場合) Future switchAccount() async { try { final account = await _signIn.signIn(); if (account != null) { print('[Gmail] アカウント切り替え:${account.email}'); return account; } else { throw Exception('ユーザーが認証をキャンセルしました'); } } catch (e) { print('[Gmail] 切り替え失敗:$e'); rethrow; } } /// Gmail API サービスインスタンスを取得・初期化 Future initializeApi() async { if (_authClient == null || _gmail != null) return; try { // credentials.json が存在する場合、OAuth2 認証を作成 if (await kIsWeb || defaultTargetPlatform == Android) { // Android では credentials.json を使用せず、GoogleSignIn のトークンを使用 print('[Gmail] GoogleSignIn のアクセストークンを使用'); // GAuthClient を生成し、GmailService を初期化 final client = GAuthClient.withCredentials( 'google_sign_in_credentials.json', // 後実装:SDK が生成するファイル名 ); _authClient = client; _gmail = GmailService(client); } else { print('[Gmail] Web/iOS モード。GoogleSignIn で管理'); } } catch (e) { print('[Gmail] API 初期化失敗:$e'); rethrow; } } /// アクセストークンを取得(GoogleSignIn から) Future getToken() async { if (_signIn.currentUser == null) return null; try { final auth = await _signIn.authenticator; return auth.accessToken.toString(); } catch (e) { print('[Gmail] トークン取得失敗:$e'); return null; } } } /// メール送信用モデル(Googleapis ライブラリの仕様に従う) class EmailMessage { String? subject; List? to; String? cc; String? bcc; String? htmlBody; EmailMessage({ this.subject, this.to, this.cc, this.bcc, this.htmlBody, }); }