package app

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"go.uber.org/zap"
)

// =============================================================================
// EXPORT DATA OPERATIONS (Profile, Collections, Metadata)
// =============================================================================

// ExportUserProfile exports the user's profile data
func (a *Application) ExportUserProfile(exportPath string) (*UserProfileExport, error) {
	a.logger.Info("Exporting user profile", zap.String("export_path", exportPath))

	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil {
		return nil, fmt.Errorf("not authenticated: %w", err)
	}

	apiClient := a.authService.GetAPIClient()
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Get user profile
	me, err := apiClient.GetMe(a.ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get user profile: %w", err)
	}

	profile := &UserProfileExport{
		ID:         me.ID,
		Email:      me.Email,
		FirstName:  me.FirstName,
		LastName:   me.LastName,
		Name:       me.Name,
		Phone:      me.Phone,
		Country:    me.Country,
		Timezone:   me.Timezone,
		CreatedAt:  me.CreatedAt.Format(time.RFC3339),
		ExportedAt: time.Now().Format(time.RFC3339),
	}

	// Save to file
	profilePath := filepath.Join(exportPath, "profile.json")
	data, err := json.MarshalIndent(profile, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("failed to marshal profile: %w", err)
	}

	if err := os.WriteFile(profilePath, data, 0644); err != nil {
		return nil, fmt.Errorf("failed to write profile file: %w", err)
	}

	a.logger.Info("User profile exported successfully", zap.String("path", profilePath))
	return profile, nil
}

// ExportCollections exports all collections (owned and shared)
func (a *Application) ExportCollections(exportPath string) (*CollectionsExport, error) {
	a.logger.Info("Exporting collections", zap.String("export_path", exportPath))

	// Get owned collections
	ownedCollections, err := a.ListCollections()
	if err != nil {
		return nil, fmt.Errorf("failed to list owned collections: %w", err)
	}

	// Get shared collections
	sharedCollections, err := a.listSharedCollections()
	if err != nil {
		a.logger.Warn("Failed to list shared collections", zap.Error(err))
		sharedCollections = []*CollectionData{}
	}

	// Convert to export format
	ownedExport := make([]*CollectionExportData, len(ownedCollections))
	for i, c := range ownedCollections {
		ownedExport[i] = &CollectionExportData{
			ID:             c.ID,
			Name:           c.Name,
			CollectionType: c.CollectionType,
			ParentID:       c.ParentID,
			FileCount:      c.TotalFiles,
			CreatedAt:      c.CreatedAt,
			ModifiedAt:     c.ModifiedAt,
			IsShared:       false,
		}
	}

	sharedExport := make([]*CollectionExportData, len(sharedCollections))
	for i, c := range sharedCollections {
		sharedExport[i] = &CollectionExportData{
			ID:             c.ID,
			Name:           c.Name,
			CollectionType: c.CollectionType,
			ParentID:       c.ParentID,
			FileCount:      c.TotalFiles,
			CreatedAt:      c.CreatedAt,
			ModifiedAt:     c.ModifiedAt,
			IsShared:       true,
		}
	}

	export := &CollectionsExport{
		OwnedCollections:  ownedExport,
		SharedCollections: sharedExport,
		TotalCount:        len(ownedExport) + len(sharedExport),
		ExportedAt:        time.Now().Format(time.RFC3339),
	}

	// Save to file
	collectionsPath := filepath.Join(exportPath, "collections.json")
	data, err := json.MarshalIndent(export, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("failed to marshal collections: %w", err)
	}

	if err := os.WriteFile(collectionsPath, data, 0644); err != nil {
		return nil, fmt.Errorf("failed to write collections file: %w", err)
	}

	a.logger.Info("Collections exported successfully",
		zap.String("path", collectionsPath),
		zap.Int("owned", len(ownedExport)),
		zap.Int("shared", len(sharedExport)))

	return export, nil
}

// ExportAllFilesMetadata exports metadata for all files in all collections
func (a *Application) ExportAllFilesMetadata(exportPath string) (*FilesMetadataExport, error) {
	a.logger.Info("Exporting all files metadata", zap.String("export_path", exportPath))

	// Get all collections
	ownedCollections, err := a.ListCollections()
	if err != nil {
		return nil, fmt.Errorf("failed to list owned collections: %w", err)
	}

	sharedCollections, err := a.listSharedCollections()
	if err != nil {
		a.logger.Warn("Failed to list shared collections", zap.Error(err))
		sharedCollections = []*CollectionData{}
	}

	allCollections := append(ownedCollections, sharedCollections...)
	allFiles := make([]*FileExportData, 0)
	var totalSize int64 = 0

	// Get files for each collection
	for _, coll := range allCollections {
		files, err := a.ListFilesByCollection(coll.ID)
		if err != nil {
			a.logger.Warn("Failed to list files for collection",
				zap.String("collection_id", coll.ID),
				zap.Error(err))
			continue
		}

		for _, f := range files {
			allFiles = append(allFiles, &FileExportData{
				ID:             f.ID,
				Filename:       f.Filename,
				MimeType:       f.ContentType,
				SizeBytes:      f.Size,
				CreatedAt:      f.CreatedAt,
				ModifiedAt:     f.ModifiedAt,
				CollectionID:   coll.ID,
				CollectionName: coll.Name,
			})
			totalSize += f.Size
		}
	}

	export := &FilesMetadataExport{
		Files:      allFiles,
		TotalCount: len(allFiles),
		TotalSize:  totalSize,
		ExportedAt: time.Now().Format(time.RFC3339),
	}

	// Save to file
	metadataPath := filepath.Join(exportPath, "files_metadata.json")
	data, err := json.MarshalIndent(export, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("failed to marshal files metadata: %w", err)
	}

	if err := os.WriteFile(metadataPath, data, 0644); err != nil {
		return nil, fmt.Errorf("failed to write files metadata file: %w", err)
	}

	a.logger.Info("Files metadata exported successfully",
		zap.String("path", metadataPath),
		zap.Int("total_files", len(allFiles)),
		zap.Int64("total_size", totalSize))

	return export, nil
}
