import type { IReactiveFileSystem } from "@firesystem/core";
import type { Project, WorkspaceSettings } from "../types";
import type { WorkspaceExport } from "./WorkspaceImporter";
import { SourceConfigBuilder } from "../credentials/SourceConfigBuilder";

export interface ExportOptions {
  includeFiles?: boolean;
  includeCredentials?: boolean;
  projectIds?: string[];
}

/**
 * Handles exporting workspace configurations
 */
export class WorkspaceExporter {
  /**
   * Export workspace to JSON
   */
  static async toJson(
    projects: Project[],
    activeProjectId: string | null,
    settings: WorkspaceSettings,
    options: ExportOptions = {}
  ): Promise<WorkspaceExport> {
    const exportedProjects = await Promise.all(
      projects
        .filter(p => !options.projectIds || options.projectIds.includes(p.id))
        .map(async p => {
          const exported: any = {
            id: p.id,
            name: p.name,
            type: p.source.type as any
          };

          // Include config based on credentials option
          if (p.source.type === "s3") {
            if (options.includeCredentials) {
              // Include full config with credentials
              exported.config = { ...p.source.config };
            } else {
              // Strip credentials from S3 config
              exported.config = {
                bucket: p.source.config.bucket,
                prefix: p.source.config.prefix
              };
            }
          } else if (p.source.type === "indexeddb") {
            exported.config = {
              dbName: p.source.config.dbName
            };
          } else {
            // For other types, include full config unless it's sensitive
            exported.config = options.includeCredentials ? 
              { ...p.source.config } : 
              SourceConfigBuilder.sanitize(p.source).config;
          }

          // Include files if requested
          if (options.includeFiles && p.fs) {
            exported.files = await this.extractFiles(p.fs);
          }

          return exported;
        })
    );

    return {
      version: "1.0",
      exportedAt: new Date(),
      workspace: {
        settings,
        activeProjectId: activeProjectId || undefined
      },
      projects: exportedProjects
    };
  }

  /**
   * Export to GitHub Gist
   */
  static async toGitHubGist(
    exportData: WorkspaceExport,
    options: {
      token: string;
      description?: string;
      public?: boolean;
    }
  ): Promise<string> {
    const response = await fetch("https://api.github.com/gists", {
      method: "POST",
      headers: {
        "Authorization": `token ${options.token}`,
        "Accept": "application/vnd.github.v3+json",
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        description: options.description || "Firesystem Workspace Export",
        public: options.public ?? false,
        files: {
          "workspace.json": {
            content: JSON.stringify(exportData, null, 2)
          }
        }
      })
    });

    if (!response.ok) {
      throw new Error(`Failed to create gist: ${response.statusText}`);
    }

    const gist = await response.json();
    return gist.id;
  }

  /**
   * Export to API endpoint
   */
  static async toApi(
    exportData: WorkspaceExport,
    url: string,
    options?: {
      headers?: Record<string, string>;
      method?: string;
    }
  ): Promise<void> {
    const response = await fetch(url, {
      method: options?.method || "POST",
      headers: {
        "Content-Type": "application/json",
        ...options?.headers
      },
      body: JSON.stringify(exportData)
    });

    if (!response.ok) {
      throw new Error(`Failed to export to API: ${response.statusText}`);
    }
  }

  /**
   * Extract all files from a file system
   */
  private static async extractFiles(fs: IReactiveFileSystem): Promise<Array<{
    path: string;
    content: string;
    metadata?: Record<string, any>;
  }>> {
    const files: any[] = [];

    try {
      // Check if file system supports glob operations
      if (!fs.capabilities?.supportsGlob) {
        console.warn("File system does not support glob operations, skipping file extraction");
        return files;
      }

      // Get all file paths
      const paths = await fs.glob("**/*");

      for (const path of paths) {
        try {
          const stat = await fs.stat(path);
          
          if (stat.type === "file") {
            const file = await fs.readFile(path);
            
            // Convert content to string if needed
            let content = file.content;
            if (typeof content !== "string") {
              content = JSON.stringify(content);
            }

            files.push({
              path,
              content,
              metadata: file.metadata
            });
          }
        } catch (error) {
          console.warn(`Failed to export file ${path}:`, error);
        }
      }
    } catch (error) {
      console.warn("Failed to glob files:", error);
    }

    return files;
  }
}