package internal

import (
	"context"

	"github.com/tech/sendico/pkg/auth"
	"github.com/tech/sendico/pkg/db/account"
	"github.com/tech/sendico/pkg/db/organization"
	"github.com/tech/sendico/pkg/db/policy"
	"github.com/tech/sendico/pkg/mlogger"
	"github.com/tech/sendico/pkg/mutil/mzap"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

// AccountManager provides helper methods for account management operations
type AccountManager struct {
	logger      mlogger.Logger
	accountDB   account.DB
	orgDB       organization.DB
	policyDB    policy.DB
	authManager auth.Manager
}

// NewAccountManager creates a new AccountManager instance
func NewAccountManager(
	logger mlogger.Logger,
	accountDB account.DB,
	orgDB organization.DB,
	policyDB policy.DB,
	authManager auth.Manager,
) *AccountManager {
	var namedLogger mlogger.Logger
	if logger != nil {
		namedLogger = logger.Named("account_manager")
	}
	return &AccountManager{
		logger:      namedLogger,
		accountDB:   accountDB,
		orgDB:       orgDB,
		policyDB:    policyDB,
		authManager: authManager,
	}
}

// DeleteOrganization deletes an organization and all its associated data
// The caller is responsible for wrapping this in a transaction
func (m *AccountManager) DeleteOrganization(ctx context.Context, orgRef bson.ObjectID) error {
	m.logger.Debug("Deleting organization", mzap.ObjRef("org_ref", orgRef))

	// Delete organization roles
	if err := m.deleteOrganizationRoles(ctx, orgRef); err != nil {
		m.logger.Warn("Failed to delete organization roles", zap.Error(err), mzap.ObjRef("org_ref", orgRef))
		return err
	}

	// Delete organization policies
	if err := m.deleteOrganizationPolicies(ctx, orgRef); err != nil {
		m.logger.Warn("Failed to delete organization policies", zap.Error(err), mzap.ObjRef("org_ref", orgRef))
		return err
	}

	// Finally delete the organization itself
	if err := m.orgDB.Delete(ctx, bson.NilObjectID, orgRef); err != nil {
		m.logger.Warn("Failed to delete organization", zap.Error(err), mzap.ObjRef("org_ref", orgRef))
		return err
	}

	m.logger.Info("Successfully deleted organization", mzap.ObjRef("org_ref", orgRef))
	return nil
}

// DeleteAccount deletes an account and all its associated data
// The caller is responsible for wrapping this in a transaction
func (m *AccountManager) DeleteAccount(ctx context.Context, accountRef bson.ObjectID) error {
	m.logger.Debug("Deleting account", mzap.AccRef(accountRef))

	// Delete the account
	if err := m.accountDB.Delete(ctx, accountRef); err != nil {
		m.logger.Warn("Failed to delete account", zap.Error(err), mzap.AccRef(accountRef))
		return err
	}

	m.logger.Info("Successfully deleted account", mzap.AccRef(accountRef))
	return nil
}

// DeleteAll deletes all data for a given account and organization
// The caller is responsible for wrapping this in a transaction
func (m *AccountManager) DeleteAll(ctx context.Context, accountRef, organizationRef bson.ObjectID) error {
	m.logger.Debug("Deleting all data", mzap.AccRef(accountRef), mzap.ObjRef("organization_ref", organizationRef))

	// Delete organization first (which will cascade delete all related data)
	if err := m.DeleteOrganization(ctx, organizationRef); err != nil {
		m.logger.Warn("Failed to delete organization", zap.Error(err), mzap.ObjRef("organization_ref", organizationRef))
		return err
	}

	// Delete account
	if err := m.DeleteAccount(ctx, accountRef); err != nil {
		m.logger.Warn("Failed to delete account", zap.Error(err), mzap.AccRef(accountRef))
		return err
	}

	m.logger.Info("Successfully deleted all data", mzap.AccRef(accountRef), mzap.ObjRef("organization_ref", organizationRef))
	return nil
}

// deleteOrganizationRoles deletes all roles for an organization
func (m *AccountManager) deleteOrganizationRoles(ctx context.Context, orgRef bson.ObjectID) error {
	// Get all roles for the organization
	roles, err := m.authManager.Role().List(ctx, orgRef)
	if err != nil {
		m.logger.Warn("Failed to list organization roles", zap.Error(err), mzap.ObjRef("org_ref", orgRef))
		return err
	}

	// Delete each role
	for _, role := range roles {
		if err := m.authManager.Role().Delete(ctx, role.ID); err != nil {
			m.logger.Warn("Failed to delete role", zap.Error(err), mzap.ObjRef("role_ref", role.ID), mzap.ObjRef("org_ref", orgRef))
			return err
		}
	}

	m.logger.Info("Successfully deleted organization roles", zap.Int("count", len(roles)), mzap.ObjRef("org_ref", orgRef))
	return nil
}

// deleteOrganizationPolicies deletes all policies for an organization
func (m *AccountManager) deleteOrganizationPolicies(_ context.Context, _ bson.ObjectID) error {
	// Note: PolicyDB is used for both roles and policies, but the interface is unclear
	// This would need to be implemented differently or skipped for now
	m.logger.Warn("Policy deletion not implemented - interface unclear")
	return nil
}
