import { Request, Response } from 'express';
import { supabase } from '../lib/supabase';
import { AuthenticatedRequest } from '../middleware/auth';
import { encryptToken, decryptToken } from '../lib/tokenCrypto';
import { createState, consumeState } from '../lib/oauthState';
import * as googleDrive from '../lib/googleDriveClient';

function callbackPage(title: string, message: string): string {
  return `<!doctype html>
<html lang="tr"><head><meta charset="utf-8"><title>${title}</title>
<style>
  body { font-family: system-ui, -apple-system, sans-serif; background: #060b14; color: #eef1f4;
    display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
  .card { max-width: 420px; text-align: center; padding: 32px; }
  h1 { font-size: 20px; margin-bottom: 12px; }
  p { color: #9ca3af; font-size: 14px; line-height: 1.6; }
</style></head>
<body><div class="card"><h1>${title}</h1><p>${message}</p></div></body></html>`;
}

// PRD §19: Electron sadece bir tarayıcı açıp Google'a yönlendirir, tüm OAuth
// kod-değişimi burada (backend'de) yapılır — Electron'a kesinlikle client
// secret veya refresh token gönderilmiyor.
export const connect = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id as string;
    const state = createState(userId);
    const authUrl = googleDrive.buildAuthUrl(state);
    res.json({ authUrl });
  } catch (error: any) {
    console.error('[DRIVE] Connect Error:', error);
    res.status(500).json({ error: 'Google Drive bağlantısı başlatılamadı.' });
  }
};

// Google'ın doğrudan tarayıcı yönlendirmesiyle çağırdığı tek public uç nokta —
// Bearer token yok, kimlik doğrulama "state" üzerinden yapılıyor (bkz. oauthState.ts).
export const oauthCallback = async (req: Request, res: Response) => {
  const { code, state, error: oauthError } = req.query as { code?: string; state?: string; error?: string };

  if (oauthError) {
    console.error('[DRIVE] Google OAuth error:', oauthError);
    return res.status(400).send(callbackPage('Bağlantı reddedildi', 'Google Drive bağlantısı tamamlanamadı. Bu pencereyi kapatıp AyrisLegal\'e dönebilirsiniz.'));
  }
  if (!code || !state) {
    return res.status(400).send(callbackPage('Geçersiz istek', 'Eksik parametre. Lütfen AyrisLegal\'den tekrar deneyin.'));
  }

  const userId = consumeState(state);
  if (!userId) {
    console.error('[DRIVE] Geçersiz veya süresi dolmuş OAuth state.');
    return res.status(400).send(callbackPage('Bağlantı süresi doldu', 'Lütfen AyrisLegal\'de "Google Drive\'a Bağlan"ı tekrar deneyin.'));
  }

  try {
    console.log('[DRIVE] OAuth started, user:', userId);
    const tokens = await googleDrive.exchangeCodeForTokens(code);
    if (!tokens.refresh_token) {
      throw new Error('Google refresh token döndürmedi.');
    }

    const email = await googleDrive.getUserEmail(tokens.access_token);
    const { rootFolderId, casesFolderId } = await googleDrive.ensureAyrisLegalFolders(tokens.access_token);

    const { error: dbError } = await supabase.from('google_drive_connections').upsert(
      {
        user_id: userId,
        google_email: email,
        access_token_encrypted: encryptToken(tokens.access_token),
        refresh_token_encrypted: encryptToken(tokens.refresh_token),
        token_expires_at: new Date(Date.now() + tokens.expires_in * 1000).toISOString(),
        scope: tokens.scope,
        drive_root_folder_id: rootFolderId,
        drive_cases_folder_id: casesFolderId,
        status: 'connected',
        updated_at: new Date().toISOString(),
      },
      { onConflict: 'user_id' }
    );
    if (dbError) throw dbError;

    console.log('[DRIVE] OAuth completed, user:', userId);
    res.send(callbackPage('Bağlantı başarılı', `Google Drive hesabınız (${email}) AyrisLegal'e bağlandı. Bu pencereyi kapatıp uygulamaya dönebilirsiniz.`));
  } catch (error: any) {
    console.error('[DRIVE] OAuth callback error:', error);
    res.status(500).send(callbackPage('Bağlantı başarısız', 'Google Drive bağlantısı sırasında bir hata oluştu. Lütfen tekrar deneyin.'));
  }
};

export const getStatus = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id;
    const { data, error } = await supabase
      .from('google_drive_connections')
      .select('google_email, status, last_sync_at, created_at')
      .eq('user_id', userId)
      .maybeSingle();
    if (error) throw error;
    if (!data) return res.json({ connected: false });
    res.json({ connected: data.status === 'connected', ...data });
  } catch (error: any) {
    console.error('[DRIVE] Get Status Error:', error);
    res.status(500).json({ error: 'Bağlantı durumu alınamadı.' });
  }
};

// PRD §22: local dosyalar VE Drive'daki backup dosyaları asla silinmiyor —
// burada sadece bağlantı/token kaydı kaldırılıyor.
export const disconnect = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id;
    const { data: connection } = await supabase
      .from('google_drive_connections')
      .select('refresh_token_encrypted')
      .eq('user_id', userId)
      .maybeSingle();

    if (connection) {
      try {
        await googleDrive.revokeToken(decryptToken(connection.refresh_token_encrypted));
      } catch (err: any) {
        console.error('[DRIVE] Revoke sırasında hata (yine de bağlantı kaldırılacak):', err.message);
      }
    }

    const { error } = await supabase.from('google_drive_connections').delete().eq('user_id', userId);
    if (error) throw error;

    console.log('[DRIVE] User disconnected:', userId);
    res.json({ ok: true });
  } catch (error: any) {
    console.error('[DRIVE] Disconnect Error:', error);
    res.status(500).json({ error: 'Bağlantı kesilemedi.' });
  }
};

// İleride upload/backup-status endpoint'lerinin (Faz 2) kullanacağı iç
// yardımcı — geçerli bir access_token döner, süresi dolmuşsa/dolmak üzereyse
// refresh_token ile otomatik yeniler (PRD §21). Kullanıcıya login sordurmaz.
export async function getValidAccessToken(userId: string): Promise<string> {
  const { data: connection, error } = await supabase
    .from('google_drive_connections')
    .select('access_token_encrypted, refresh_token_encrypted, token_expires_at, status')
    .eq('user_id', userId)
    .maybeSingle();
  if (error || !connection) {
    throw new Error('Google Drive bağlantısı bulunamadı.');
  }
  if (connection.status === 'reauthorization_required') {
    throw new Error('Google Drive bağlantınızın yenilenmesi gerekiyor.');
  }

  const expiresAt = new Date(connection.token_expires_at).getTime();
  if (expiresAt - Date.now() > 60_000) {
    return decryptToken(connection.access_token_encrypted);
  }

  try {
    const refreshToken = decryptToken(connection.refresh_token_encrypted);
    const refreshed = await googleDrive.refreshAccessToken(refreshToken);
    console.log('[DRIVE] Token refreshed, user:', userId);
    await supabase
      .from('google_drive_connections')
      .update({
        access_token_encrypted: encryptToken(refreshed.access_token),
        token_expires_at: new Date(Date.now() + refreshed.expires_in * 1000).toISOString(),
        updated_at: new Date().toISOString(),
      })
      .eq('user_id', userId);
    return refreshed.access_token;
  } catch (err: any) {
    if (err.code === 'invalid_grant') {
      await supabase.from('google_drive_connections').update({ status: 'reauthorization_required' }).eq('user_id', userId);
    }
    throw new Error('Google Drive bağlantınızın yenilenmesi gerekiyor.');
  }
}

export const refresh = async (req: AuthenticatedRequest, res: Response) => {
  try {
    await getValidAccessToken(req.user?.id as string);
    res.json({ ok: true });
  } catch (error: any) {
    console.error('[DRIVE] Refresh Error:', error);
    res.status(409).json({ error: error.message || 'Google Drive bağlantısı yenilenemedi.' });
  }
};

// Electron'un backupQueue.js'i tek bir dosyayı burada yükler — Google Drive
// çağrısı (resumable upload) tamamen burada yapılıyor, Electron hiçbir zaman
// Google token'ı görmüyor. PRD §9: local yapı korunuyor, dava başlığı = Drive
// klasör adı (Davalar/<dava başlığı>/<dosya>).
export const uploadFile = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id as string;
    const file = req.file;
    const { case_title, local_path, local_modified_at, sha256 } = req.body || {};

    if (!file || !case_title || !local_path) {
      return res.status(400).json({ error: 'file, case_title ve local_path zorunludur.' });
    }

    const { data: connection } = await supabase
      .from('google_drive_connections')
      .select('drive_cases_folder_id, status')
      .eq('user_id', userId)
      .maybeSingle();
    if (!connection || connection.status !== 'connected' || !connection.drive_cases_folder_id) {
      return res.status(409).json({ error: 'Google Drive bağlantısı bulunamadı.' });
    }

    let accessToken: string;
    try {
      accessToken = await getValidAccessToken(userId);
    } catch (err: any) {
      return res.status(409).json({ error: err.message || 'Google Drive bağlantınızın yenilenmesi gerekiyor.' });
    }

    const caseFolderId = await googleDrive.findOrCreateCaseFolder(accessToken, connection.drive_cases_folder_id, case_title);

    const { data: existingFile } = await supabase
      .from('google_drive_files')
      .select('id, drive_file_id')
      .eq('user_id', userId)
      .eq('local_path', local_path)
      .maybeSingle();

    console.log('[DRIVE] Upload started:', local_path);
    await supabase.from('google_drive_backup_events').insert({
      user_id: userId,
      file_id: existingFile?.id || null,
      event_type: 'upload_started',
      file_size: file.size,
    });

    let driveResult;
    try {
      driveResult = await googleDrive.uploadFileResumable(accessToken, {
        name: file.originalname,
        parentId: caseFolderId,
        mimeType: file.mimetype || 'application/octet-stream',
        buffer: file.buffer,
        existingFileId: existingFile?.drive_file_id || undefined,
      });
    } catch (uploadErr: any) {
      console.error('[DRIVE] Upload failed:', local_path, uploadErr.message);
      await supabase.from('google_drive_backup_events').insert({
        user_id: userId,
        file_id: existingFile?.id || null,
        event_type: 'upload_failed',
        file_size: file.size,
        error_message: uploadErr.message,
      });
      throw uploadErr;
    }

    const { data: fileRow, error: upsertError } = await supabase
      .from('google_drive_files')
      .upsert(
        {
          user_id: userId,
          local_path,
          drive_file_id: driveResult.id,
          drive_parent_id: caseFolderId,
          file_name: file.originalname,
          file_size: file.size,
          local_modified_at: local_modified_at || null,
          drive_modified_at: new Date().toISOString(),
          sha256: sha256 || null,
          status: 'synced',
          updated_at: new Date().toISOString(),
        },
        { onConflict: 'user_id,local_path' }
      )
      .select('id')
      .single();
    if (upsertError) throw upsertError;

    await supabase.from('google_drive_backup_events').insert({
      user_id: userId,
      file_id: fileRow.id,
      event_type: 'upload_completed',
      file_size: file.size,
      status: 'synced',
    });
    await supabase.from('google_drive_connections').update({ last_sync_at: new Date().toISOString() }).eq('user_id', userId);

    console.log('[DRIVE] Upload completed:', local_path);
    res.json({ ok: true, drive_file_id: driveResult.id });
  } catch (error: any) {
    console.error('[DRIVE] Upload Error:', error);
    // PRD §41: teknik detay kullanıcıya gitmiyor, sadece backend logunda kalıyor.
    res.status(500).json({ error: 'Dosya yedeklenemedi. İnternet bağlantınızı kontrol edin.' });
  }
};

export const getBackupStatus = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id;
    const { data: files, error } = await supabase
      .from('google_drive_files')
      .select('status, file_size')
      .eq('user_id', userId);
    if (error) throw error;

    const { data: connection } = await supabase
      .from('google_drive_connections')
      .select('last_sync_at')
      .eq('user_id', userId)
      .maybeSingle();

    const synced = (files || []).filter((f) => f.status === 'synced');
    const totalSize = synced.reduce((sum, f) => sum + (f.file_size || 0), 0);

    res.json({
      total_files: synced.length,
      total_size: totalSize,
      last_sync_at: connection?.last_sync_at || null,
    });
  } catch (error: any) {
    console.error('[DRIVE] Get Backup Status Error:', error);
    res.status(500).json({ error: 'Yedekleme durumu alınamadı.' });
  }
};

// Faz 3 — Restore. PRD §28: "Google Drive Backup — N dosya bulundu [Geri Yükle]".
// Electron'un restoreQueue.js'i bu listeyi çekip yerelde hangi dosyaların eksik
// olduğuna kendisi karar veriyor (backend local diski bilmiyor).
export const listBackupFiles = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id;
    const { data, error } = await supabase
      .from('google_drive_files')
      .select('local_path, file_name, drive_file_id, file_size, drive_modified_at')
      .eq('user_id', userId)
      .eq('status', 'synced')
      .order('local_path', { ascending: true });
    if (error) throw error;
    res.json({ files: data || [] });
  } catch (error: any) {
    console.error('[DRIVE] List Backup Files Error:', error);
    res.status(500).json({ error: 'Yedeklenen dosya listesi alınamadı.' });
  }
};

// Tek bir dosyayı Drive'dan indirip ham baytları döner. PRD §39: kullanıcı
// başka bir kullanıcının backup'ını indiremesin — bu yüzden istenen
// drive_file_id'nin gerçekten bu kullanıcının google_drive_files kaydında
// olduğu ÖNCE doğrulanıyor (aksi halde herhangi bir Drive dosya ID'si verilip
// backend'in geçerli token'ı üzerinden başkasının verisi sızdırılabilirdi).
export const downloadFile = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const userId = req.user?.id as string;
    const driveFileId = String(req.query.drive_file_id || '');
    if (!driveFileId) {
      return res.status(400).json({ error: 'drive_file_id zorunludur.' });
    }

    const { data: fileRow } = await supabase
      .from('google_drive_files')
      .select('id, file_name')
      .eq('user_id', userId)
      .eq('drive_file_id', driveFileId)
      .maybeSingle();
    if (!fileRow) {
      return res.status(403).json({ error: 'Bu dosyaya erişim yetkiniz yok.' });
    }

    let accessToken: string;
    try {
      accessToken = await getValidAccessToken(userId);
    } catch (err: any) {
      return res.status(409).json({ error: err.message || 'Google Drive bağlantınızın yenilenmesi gerekiyor.' });
    }

    const buffer = await googleDrive.downloadFile(accessToken, driveFileId);
    res.setHeader('Content-Type', 'application/octet-stream');
    res.send(buffer);
  } catch (error: any) {
    console.error('[DRIVE] Download Error:', error);
    res.status(500).json({ error: 'Dosya indirilemedi.' });
  }
};
