'use client';

// Server-backed persistence layer — wraps local IndexedDB + remote API.
// Strategy:
// - "auto" mode: if logged in → server; otherwise local
// - "server" mode: server only (local cache only)
// - "local" mode: local only
//
// Storage mode is per-user setting in useAuth store.

import * as local from './persistence';
import * as server from '@/lib/api/auth-client';
import type { StoredProjectRecord, ProjectSummary } from './persistence';

export type Mode = 'auto' | 'local' | 'server';

export interface ServerProject {
  project: unknown;
  assetsMeta: { id: string; size: number }[];
}

function shouldUseServer(
  mode: Mode,
  isLoggedIn: boolean,
): boolean {
  if (mode === 'server') return isLoggedIn;
  if (mode === 'local') return false;
  return isLoggedIn; // auto
}

// ===== Projects =====

export async function saveProject(
  projectId: string,
  name: string,
  createdAt: number,
  snapshot: Omit<StoredProjectRecord, 'id' | 'name' | 'createdAt' | 'updatedAt'>,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<number> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    const updatedAt = Date.now();
    // Server stores full project JSON in one record.
    const project = { ...snapshot, id: projectId, name, createdAt, updatedAt };
    // PUT or POST? Check if it already exists.
    try {
      await server.updateServerProject(projectId, project);
    } catch (err) {
      // If 404 → create new
      const msg = err instanceof Error ? err.message : '';
      if (msg.includes('ไม่พบโปรเจกต์') || msg.includes('404')) {
        await server.createServerProject(name, project);
      } else {
        throw err;
      }
    }
    // Always mirror locally for offline access.
    try {
      await local.saveProject(projectId, name, createdAt, snapshot);
    } catch {}
    return updatedAt;
  }
  return local.saveProject(projectId, name, createdAt, snapshot);
}

export async function loadProject(
  projectId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<StoredProjectRecord | null> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    const res = await server.getServerProject(projectId);
    if (!res) return null;
    return res.project as StoredProjectRecord;
  }
  return local.loadProject(projectId);
}

export async function listProjects(
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<ProjectSummary[]> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    try {
      const list = await server.listServerProjects();
      return list.map((p) => ({
        id: p.id,
        name: p.name,
        updatedAt: p.updatedAt,
        clipCount: p.clipsCount,
      }));
    } catch {
      return [];
    }
  }
  return local.listProjects();
}

export async function deleteProject(
  projectId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<void> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    try { await server.deleteServerProject(projectId); } catch {}
  }
  try { await local.deleteProject(projectId); } catch {}
}

// ===== Asset blobs =====

export async function saveAssetBlob(
  projectId: string,
  assetId: string,
  file: Blob,
  audioBuffer: ArrayBuffer | undefined,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<void> {
  // Always save locally for offline + speed.
  try {
    await local.saveAssetBlob(projectId, assetId, file, audioBuffer);
  } catch {}
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    try {
      await server.uploadServerAsset(projectId, assetId, file);
    } catch (err) {
      console.warn('[server] asset upload failed', err);
    }
  }
}

export async function loadAssetBlob(
  projectId: string,
  assetId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<{ file: Blob; audioBuffer?: ArrayBuffer } | null> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    // Try local first (faster), fall back to server.
    const localBlob = await local.loadAssetBlob(projectId, assetId);
    if (localBlob) return localBlob;
    const remote = await server.downloadServerAsset(projectId, assetId);
    if (!remote) return null;
    return { file: remote };
  }
  return local.loadAssetBlob(projectId, assetId);
}

export async function deleteAssetBlob(
  projectId: string,
  assetId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<void> {
  try { await local.deleteAssetBlob(projectId, assetId); } catch {}
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    try { await server.deleteServerAsset(projectId, assetId); } catch {}
  }
}

export async function deleteAllBlobsForProject(
  projectId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<void> {
  try { await local.deleteAllBlobsForProject(projectId); } catch {}
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    // Server-side: this is done via project delete, so no-op here.
  }
}

export async function listAssetIdsForProject(
  projectId: string,
  ctx: { mode: Mode; isLoggedIn: boolean },
): Promise<string[]> {
  if (shouldUseServer(ctx.mode, ctx.isLoggedIn)) {
    try {
      const res = await server.getServerProject(projectId);
      if (!res) return [];
      return res.assetsMeta.map((m) => m.id);
    } catch {
      return [];
    }
  }
  return local.listAssetIdsForProject(projectId);
}

export async function setCurrentProjectId(id: string): Promise<void> {
  return local.setCurrentProjectId(id);
}

export async function getCurrentProjectId(): Promise<string | null> {
  return local.getCurrentProjectId();
}
