package repository

import (
	"aggios-app/backend/internal/domain"
	"database/sql"
	"fmt"
	"log"

	"github.com/lib/pq"
)

type CRMRepository struct {
	db *sql.DB
}

func NewCRMRepository(db *sql.DB) *CRMRepository {
	return &CRMRepository{db: db}
}

// ==================== CUSTOMERS ====================

func (r *CRMRepository) CreateCustomer(customer *domain.CRMCustomer) error {
	query := `
		INSERT INTO crm_customers (
			id, tenant_id, name, email, phone, company, position,
			address, city, state, zip_code, country, notes, tags,
			is_active, created_by, logo_url
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
		RETURNING created_at, updated_at
	`

	// Handle optional created_by field (NULL for public registrations)
	var createdBy interface{}
	if customer.CreatedBy != "" {
		createdBy = customer.CreatedBy
	} else {
		createdBy = nil
	}

	return r.db.QueryRow(
		query,
		customer.ID, customer.TenantID, customer.Name, customer.Email, customer.Phone,
		customer.Company, customer.Position, customer.Address, customer.City, customer.State,
		customer.ZipCode, customer.Country, customer.Notes, pq.Array(customer.Tags),
		customer.IsActive, createdBy, customer.LogoURL,
	).Scan(&customer.CreatedAt, &customer.UpdatedAt)
}

func (r *CRMRepository) GetCustomersByTenant(tenantID string) ([]domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, phone, company, position,
		       address, city, state, zip_code, country, notes, tags,
		       is_active, COALESCE(created_by::text, '') AS created_by, created_at, updated_at,
			   COALESCE(logo_url, '') as logo_url
		FROM crm_customers
		WHERE tenant_id = $1 AND is_active = true
		ORDER BY created_at DESC
	`

	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var customers []domain.CRMCustomer
	for rows.Next() {
		var c domain.CRMCustomer
		err := rows.Scan(
			&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
			&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
			&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt, &c.LogoURL,
		)
		if err != nil {
			return nil, err
		}
		customers = append(customers, c)
	}

	return customers, nil
}

func (r *CRMRepository) GetCustomerByID(id string, tenantID string) (*domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, phone, company, position,
		       address, city, state, zip_code, country, notes, tags,
		       is_active, COALESCE(created_by::text, '') AS created_by, created_at, updated_at,
			   COALESCE(logo_url, '') as logo_url
		FROM crm_customers
		WHERE id = $1 AND tenant_id = $2
	`

	var c domain.CRMCustomer
	err := r.db.QueryRow(query, id, tenantID).Scan(
		&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
		&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
		&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt, &c.LogoURL,
	)

	if err != nil {
		return nil, err
	}

	return &c, nil
}

func (r *CRMRepository) UpdateCustomer(customer *domain.CRMCustomer) error {
	query := `
		UPDATE crm_customers SET
			name = $1, email = $2, phone = $3, company = $4, position = $5,
			address = $6, city = $7, state = $8, zip_code = $9, country = $10,
			notes = $11, tags = $12, is_active = $13, logo_url = $14
		WHERE id = $15 AND tenant_id = $16
	`

	result, err := r.db.Exec(
		query,
		customer.Name, customer.Email, customer.Phone, customer.Company, customer.Position,
		customer.Address, customer.City, customer.State, customer.ZipCode, customer.Country,
		customer.Notes, pq.Array(customer.Tags), customer.IsActive, customer.LogoURL,
		customer.ID, customer.TenantID,
	)

	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return fmt.Errorf("customer not found")
	}

	return nil
}

func (r *CRMRepository) DeleteCustomer(id string, tenantID string) error {
	query := `DELETE FROM crm_customers WHERE id = $1 AND tenant_id = $2`

	result, err := r.db.Exec(query, id, tenantID)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return fmt.Errorf("customer not found")
	}

	return nil
}

// ==================== LISTS ====================

func (r *CRMRepository) CreateList(list *domain.CRMList) error {
	query := `
		INSERT INTO crm_lists (id, tenant_id, customer_id, funnel_id, name, description, color, created_by)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
		RETURNING created_at, updated_at
	`

	return r.db.QueryRow(
		query,
		list.ID, list.TenantID, list.CustomerID, list.FunnelID, list.Name, list.Description, list.Color, list.CreatedBy,
	).Scan(&list.CreatedAt, &list.UpdatedAt)
}

func (r *CRMRepository) GetListsByTenant(tenantID string) ([]domain.CRMListWithCustomers, error) {
	query := `
		SELECT l.id, l.tenant_id, l.customer_id, l.funnel_id, l.name, l.description, l.color, l.created_by,
			   l.created_at, l.updated_at,
			   COALESCE(c.name, '') as customer_name,
			   (SELECT COUNT(*) FROM crm_customer_lists cl WHERE cl.list_id = l.id) as customer_count,
			   (SELECT COUNT(*) FROM crm_lead_lists ll WHERE ll.list_id = l.id) as lead_count
		FROM crm_lists l
		LEFT JOIN crm_customers c ON l.customer_id = c.id
		WHERE l.tenant_id = $1
		ORDER BY l.created_at DESC
	`

	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var lists []domain.CRMListWithCustomers
	for rows.Next() {
		var l domain.CRMListWithCustomers
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.CustomerID, &l.FunnelID, &l.Name, &l.Description, &l.Color, &l.CreatedBy,
			&l.CreatedAt, &l.UpdatedAt, &l.CustomerName, &l.CustomerCount, &l.LeadCount,
		)
		if err != nil {
			return nil, err
		}
		lists = append(lists, l)
	}

	return lists, nil
}

func (r *CRMRepository) GetListByID(id string, tenantID string) (*domain.CRMList, error) {
	query := `
		SELECT id, tenant_id, customer_id, funnel_id, name, description, color, created_by, created_at, updated_at
		FROM crm_lists
		WHERE id = $1 AND tenant_id = $2
	`

	var l domain.CRMList
	err := r.db.QueryRow(query, id, tenantID).Scan(
		&l.ID, &l.TenantID, &l.CustomerID, &l.FunnelID, &l.Name, &l.Description, &l.Color, &l.CreatedBy,
		&l.CreatedAt, &l.UpdatedAt,
	)

	if err != nil {
		return nil, err
	}

	return &l, nil
}

func (r *CRMRepository) UpdateList(list *domain.CRMList) error {
	query := `
		UPDATE crm_lists SET
			name = $1, description = $2, color = $3, customer_id = $4, funnel_id = $5
		WHERE id = $6 AND tenant_id = $7
	`

	result, err := r.db.Exec(query, list.Name, list.Description, list.Color, list.CustomerID, list.FunnelID, list.ID, list.TenantID)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return fmt.Errorf("list not found")
	}

	return nil
}

func (r *CRMRepository) DeleteList(id string, tenantID string) error {
	query := `DELETE FROM crm_lists WHERE id = $1 AND tenant_id = $2`

	result, err := r.db.Exec(query, id, tenantID)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}

	if rows == 0 {
		return fmt.Errorf("list not found")
	}

	return nil
}

// ==================== CUSTOMER <-> LIST ====================

func (r *CRMRepository) AddCustomerToList(customerID, listID, addedBy string) error {
	query := `
		INSERT INTO crm_customer_lists (customer_id, list_id, added_by)
		VALUES ($1, $2, $3)
		ON CONFLICT (customer_id, list_id) DO NOTHING
	`

	_, err := r.db.Exec(query, customerID, listID, addedBy)
	return err
}

func (r *CRMRepository) RemoveCustomerFromList(customerID, listID string) error {
	query := `DELETE FROM crm_customer_lists WHERE customer_id = $1 AND list_id = $2`

	_, err := r.db.Exec(query, customerID, listID)
	return err
}

func (r *CRMRepository) GetCustomerLists(customerID string) ([]domain.CRMList, error) {
	query := `
		SELECT l.id, l.tenant_id, l.name, l.description, l.color, l.created_by,
			   l.created_at, l.updated_at
		FROM crm_lists l
		INNER JOIN crm_customer_lists cl ON l.id = cl.list_id
		WHERE cl.customer_id = $1
		ORDER BY l.name
	`

	rows, err := r.db.Query(query, customerID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var lists []domain.CRMList
	for rows.Next() {
		var l domain.CRMList
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.Name, &l.Description, &l.Color, &l.CreatedBy,
			&l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		lists = append(lists, l)
	}

	return lists, nil
}

func (r *CRMRepository) GetListCustomers(listID string, tenantID string) ([]domain.CRMCustomer, error) {
	query := `
		SELECT c.id, c.tenant_id, c.name, c.email, c.phone, c.company, c.position,
			   c.address, c.city, c.state, c.zip_code, c.country, c.notes, c.tags,
			   c.is_active, c.created_by, c.created_at, c.updated_at,
			   COALESCE(c.logo_url, '') as logo_url
		FROM crm_customers c
		INNER JOIN crm_customer_lists cl ON c.id = cl.customer_id
		WHERE cl.list_id = $1 AND c.tenant_id = $2 AND c.is_active = true
		ORDER BY c.name
	`

	rows, err := r.db.Query(query, listID, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var customers []domain.CRMCustomer
	for rows.Next() {
		var c domain.CRMCustomer
		err := rows.Scan(
			&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
			&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
			&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt, &c.LogoURL,
		)
		if err != nil {
			return nil, err
		}
		customers = append(customers, c)
	}

	return customers, nil
}

// ==================== LEADS ====================

func (r *CRMRepository) CreateLead(lead *domain.CRMLead) error {
	query := `
		INSERT INTO crm_leads (
			id, tenant_id, customer_id, funnel_id, stage_id, name, email, phone, source, source_meta,
			status, notes, tags, is_active, created_by
		) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
		RETURNING created_at, updated_at
	`

	return r.db.QueryRow(
		query,
		lead.ID, lead.TenantID, lead.CustomerID, lead.FunnelID, lead.StageID, lead.Name, lead.Email, lead.Phone,
		lead.Source, lead.SourceMeta, lead.Status, lead.Notes, pq.Array(lead.Tags),
		lead.IsActive, lead.CreatedBy,
	).Scan(&lead.CreatedAt, &lead.UpdatedAt)
}
func (r *CRMRepository) AddLeadToList(leadID, listID, addedBy string) error {
	query := `
		INSERT INTO crm_lead_lists (lead_id, list_id, added_by)
		VALUES ($1, $2, $3)
		ON CONFLICT (lead_id, list_id) DO NOTHING
	`
	_, err := r.db.Exec(query, leadID, listID, addedBy)
	return err
}

func (r *CRMRepository) BulkAddLeadsToList(leadIDs []string, listID string, addedBy string) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	stmt, err := tx.Prepare(pq.CopyIn("crm_lead_lists", "lead_id", "list_id", "added_by"))
	if err != nil {
		return err
	}
	defer stmt.Close()

	for _, leadID := range leadIDs {
		_, err = stmt.Exec(leadID, listID, addedBy)
		if err != nil {
			return err
		}
	}

	_, err = stmt.Exec()
	if err != nil {
		return err
	}

	return tx.Commit()
}

func (r *CRMRepository) BulkCreateLeads(leads []domain.CRMLead) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	query := `
		INSERT INTO crm_leads (
			id, tenant_id, customer_id, funnel_id, stage_id, name, email, phone, source, 
			source_meta, status, notes, tags, is_active, created_by
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
		) ON CONFLICT (tenant_id, email) DO UPDATE SET
			customer_id = COALESCE(EXCLUDED.customer_id, crm_leads.customer_id),
			funnel_id = COALESCE(EXCLUDED.funnel_id, crm_leads.funnel_id),
			stage_id = COALESCE(EXCLUDED.stage_id, crm_leads.stage_id),
			name = COALESCE(EXCLUDED.name, crm_leads.name),
			phone = COALESCE(EXCLUDED.phone, crm_leads.phone),
			source = EXCLUDED.source,
			source_meta = EXCLUDED.source_meta,
			status = EXCLUDED.status,
			notes = COALESCE(EXCLUDED.notes, crm_leads.notes),
			tags = EXCLUDED.tags,
			updated_at = CURRENT_TIMESTAMP
		RETURNING id
	`

	stmt, err := tx.Prepare(query)
	if err != nil {
		return err
	}
	defer stmt.Close()

	for i := range leads {
		var returnedID string
		err = stmt.QueryRow(
			leads[i].ID, leads[i].TenantID, leads[i].CustomerID, leads[i].FunnelID, leads[i].StageID, leads[i].Name, leads[i].Email, leads[i].Phone,
			leads[i].Source, string(leads[i].SourceMeta), leads[i].Status, leads[i].Notes, pq.Array(leads[i].Tags),
			leads[i].IsActive, leads[i].CreatedBy,
		).Scan(&returnedID)
		if err != nil {
			return err
		}
		// Atualiza o ID do lead com o ID retornado (pode ser diferente em caso de conflito)
		leads[i].ID = returnedID
	}

	return tx.Commit()
}

func (r *CRMRepository) GetLeadsByTenant(tenantID string) ([]domain.CRMLead, error) {
	query := `
		SELECT id, tenant_id, customer_id, funnel_id, stage_id, name, email, phone, source, source_meta,
		       status, COALESCE(notes, ''), tags, is_active, created_by, created_at, updated_at
		FROM crm_leads
		WHERE tenant_id = $1 AND is_active = true
		ORDER BY created_at DESC
	`

	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var leads []domain.CRMLead
	for rows.Next() {
		var l domain.CRMLead
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.CustomerID, &l.FunnelID, &l.StageID, &l.Name, &l.Email, &l.Phone, &l.Source, &l.SourceMeta,
			&l.Status, &l.Notes, pq.Array(&l.Tags), &l.IsActive, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			log.Printf("Error scanning lead: %v", err)
			continue
		}
		leads = append(leads, l)
	}

	return leads, nil
}

func (r *CRMRepository) GetLeadsWithListsByTenant(tenantID string) ([]domain.CRMLeadWithLists, error) {
	leads, err := r.GetLeadsByTenant(tenantID)
	if err != nil {
		return nil, err
	}

	var leadsWithLists []domain.CRMLeadWithLists
	for _, l := range leads {
		lists, err := r.GetListsByLeadID(l.ID)
		if err != nil {
			lists = []domain.CRMList{}
		}
		leadsWithLists = append(leadsWithLists, domain.CRMLeadWithLists{
			CRMLead: l,
			Lists:   lists,
		})
	}

	return leadsWithLists, nil
}

func (r *CRMRepository) GetListsByLeadID(leadID string) ([]domain.CRMList, error) {
	query := `
		SELECT l.id, l.tenant_id, l.customer_id, l.name, l.description, l.color, l.created_by, l.created_at, l.updated_at
		FROM crm_lists l
		JOIN crm_lead_lists cll ON l.id = cll.list_id
		WHERE cll.lead_id = $1
	`

	rows, err := r.db.Query(query, leadID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var lists []domain.CRMList
	for rows.Next() {
		var l domain.CRMList
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.CustomerID, &l.Name, &l.Description, &l.Color, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		lists = append(lists, l)
	}

	return lists, nil
}

func (r *CRMRepository) GetLeadByID(id string, tenantID string) (*domain.CRMLead, error) {
	query := `
		SELECT id, tenant_id, customer_id, funnel_id, stage_id, name, email, phone, source, source_meta,
		       status, COALESCE(notes, ''), tags, is_active, created_by, created_at, updated_at
		FROM crm_leads
		WHERE id = $1 AND tenant_id = $2
	`

	var l domain.CRMLead
	err := r.db.QueryRow(query, id, tenantID).Scan(
		&l.ID, &l.TenantID, &l.CustomerID, &l.FunnelID, &l.StageID, &l.Name, &l.Email, &l.Phone, &l.Source, &l.SourceMeta,
		&l.Status, &l.Notes, pq.Array(&l.Tags), &l.IsActive, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}

	return &l, nil
}

func (r *CRMRepository) UpdateLead(lead *domain.CRMLead) error {
	query := `
		UPDATE crm_leads SET
			customer_id = $1,
			funnel_id = $2,
			stage_id = $3,
			name = $4,
			email = $5,
			phone = $6,
			source = $7,
			source_meta = $8,
			status = $9,
			notes = $10,
			tags = $11,
			is_active = $12
		WHERE id = $13 AND tenant_id = $14
	`

	result, err := r.db.Exec(
		query,
		lead.CustomerID, lead.FunnelID, lead.StageID, lead.Name, lead.Email, lead.Phone, lead.Source, lead.SourceMeta,
		lead.Status, lead.Notes, pq.Array(lead.Tags), lead.IsActive,
		lead.ID, lead.TenantID,
	)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}
	if rows == 0 {
		return fmt.Errorf("lead not found")
	}

	return nil
}

func (r *CRMRepository) DeleteLead(id string, tenantID string) error {
	query := `DELETE FROM crm_leads WHERE id = $1 AND tenant_id = $2`
	result, err := r.db.Exec(query, id, tenantID)
	if err != nil {
		return err
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return err
	}
	if rows == 0 {
		return fmt.Errorf("lead not found")
	}
	return nil
}

func (r *CRMRepository) GetLeadByEmailOrPhone(tenantID, email, phone string) (*domain.CRMLead, error) {
	query := `
		SELECT id, tenant_id, customer_id, name, email, phone, source, source_meta,
		       status, COALESCE(notes, ''), tags, is_active, created_by, created_at, updated_at
		FROM crm_leads
		WHERE tenant_id = $1
		  AND (
			(email IS NOT NULL AND $2 <> '' AND LOWER(email) = LOWER($2))
			OR (phone IS NOT NULL AND $3 <> '' AND phone = $3)
		  )
		ORDER BY created_at DESC
		LIMIT 1
	`

	var l domain.CRMLead
	err := r.db.QueryRow(query, tenantID, email, phone).Scan(
		&l.ID, &l.TenantID, &l.CustomerID, &l.Name, &l.Email, &l.Phone, &l.Source, &l.SourceMeta,
		&l.Status, &l.Notes, pq.Array(&l.Tags), &l.IsActive, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}

	return &l, nil
}

func (r *CRMRepository) RemoveLeadFromList(leadID, listID string) error {
	query := `DELETE FROM crm_lead_lists WHERE lead_id = $1 AND list_id = $2`
	_, err := r.db.Exec(query, leadID, listID)
	return err
}

func (r *CRMRepository) GetLeadLists(leadID string) ([]domain.CRMList, error) {
	query := `
		SELECT l.id, l.tenant_id, l.name, COALESCE(l.description, ''), l.color, l.created_by,
		       l.created_at, l.updated_at
		FROM crm_lists l
		INNER JOIN crm_lead_lists ll ON l.id = ll.list_id
		WHERE ll.lead_id = $1
		ORDER BY l.name
	`

	rows, err := r.db.Query(query, leadID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var lists []domain.CRMList
	for rows.Next() {
		var l domain.CRMList
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.Name, &l.Description, &l.Color, &l.CreatedBy,
			&l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		lists = append(lists, l)
	}

	return lists, nil
}

func (r *CRMRepository) GetListByName(tenantID, name string) (*domain.CRMList, error) {
	query := `
		SELECT id, tenant_id, name, description, color, created_by, created_at, updated_at
		FROM crm_lists
		WHERE tenant_id = $1 AND LOWER(name) = LOWER($2)
		LIMIT 1
	`

	var l domain.CRMList
	err := r.db.QueryRow(query, tenantID, name).Scan(
		&l.ID, &l.TenantID, &l.Name, &l.Description, &l.Color, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
	)
	if err != nil {
		return nil, err
	}
	return &l, nil
}

// CreateShareToken cria um novo token de compartilhamento
func (r *CRMRepository) CreateShareToken(token *domain.CRMShareToken) error {
	query := `
		INSERT INTO crm_share_tokens (id, tenant_id, customer_id, token, expires_at, created_by, created_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
	`
	_, err := r.db.Exec(query, token.ID, token.TenantID, token.CustomerID, token.Token, token.ExpiresAt, token.CreatedBy, token.CreatedAt)
	return err
}

// GetShareTokenByToken busca um token de compartilhamento pelo token
func (r *CRMRepository) GetShareTokenByToken(token string) (*domain.CRMShareToken, error) {
	query := `
		SELECT id, tenant_id, customer_id, token, expires_at, created_by, created_at
		FROM crm_share_tokens
		WHERE token = $1
	`

	var st domain.CRMShareToken
	err := r.db.QueryRow(query, token).Scan(
		&st.ID, &st.TenantID, &st.CustomerID, &st.Token, &st.ExpiresAt, &st.CreatedBy, &st.CreatedAt,
	)
	if err != nil {
		return nil, err
	}
	return &st, nil
}

// GetLeadsByCustomerID retorna todos os leads de um cliente específico
func (r *CRMRepository) GetLeadsByCustomerID(customerID string) ([]domain.CRMLead, error) {
	query := `
		SELECT id, tenant_id, customer_id, name, email, phone, source, source_meta,
		       status, notes, tags, is_active, created_by, created_at, updated_at
		FROM crm_leads
		WHERE customer_id = $1 AND is_active = true
		ORDER BY created_at DESC
	`

	rows, err := r.db.Query(query, customerID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var leads []domain.CRMLead
	for rows.Next() {
		var l domain.CRMLead
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.CustomerID, &l.Name, &l.Email, &l.Phone, &l.Source, &l.SourceMeta,
			&l.Status, &l.Notes, &l.Tags, &l.IsActive, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		leads = append(leads, l)
	}

	if leads == nil {
		leads = []domain.CRMLead{}
	}

	return leads, nil
}

// GetListsByCustomerID retorna todas as listas que possuem leads de um cliente específico
func (r *CRMRepository) GetListsByCustomerID(customerID string) ([]domain.CRMList, error) {
	query := `
		SELECT DISTINCT l.id, l.tenant_id, l.name, l.description, l.color, l.created_by,
		       l.created_at, l.updated_at
		FROM crm_lists l
		INNER JOIN crm_lead_lists ll ON l.id = ll.list_id
		INNER JOIN crm_leads le ON ll.lead_id = le.id
		WHERE le.customer_id = $1
		ORDER BY l.name
	`

	rows, err := r.db.Query(query, customerID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var lists []domain.CRMList
	for rows.Next() {
		var l domain.CRMList
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.Name, &l.Description, &l.Color, &l.CreatedBy,
			&l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		lists = append(lists, l)
	}

	if lists == nil {
		lists = []domain.CRMList{}
	}

	return lists, nil
}

// GetCustomerByEmail busca um cliente pelo email
func (r *CRMRepository) GetCustomerByEmail(email string) (*domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, 
		       COALESCE(phone, '') as phone, 
		       COALESCE(company, '') as company, 
		       COALESCE(position, '') as position,
			   COALESCE(address, '') as address, 
			   COALESCE(city, '') as city, 
			   COALESCE(state, '') as state, 
			   COALESCE(zip_code, '') as zip_code, 
			   COALESCE(country, '') as country, 
			   COALESCE(notes, '{}') as notes, 
			   COALESCE(tags, '{}') as tags,
			   is_active, 
			   created_by, 
			   created_at, 
			   updated_at,
			   COALESCE(password_hash, '') as password_hash, 
			   has_portal_access, 
			   portal_last_login, 
			   portal_created_at
		FROM crm_customers
		WHERE email = $1 AND is_active = true
	`

	var c domain.CRMCustomer
	var createdBy sql.NullString
	err := r.db.QueryRow(query, email).Scan(
		&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
		&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
		&c.IsActive, &createdBy, &c.CreatedAt, &c.UpdatedAt,
		&c.PasswordHash, &c.HasPortalAccess, &c.PortalLastLogin, &c.PortalCreatedAt,
	)

	if err != nil {
		return nil, err
	}

	if createdBy.Valid {
		c.CreatedBy = createdBy.String
	}

	return &c, nil
}

// UpdateCustomerLastLogin atualiza o último login do cliente no portal
func (r *CRMRepository) UpdateCustomerLastLogin(customerID string) error {
	query := `UPDATE crm_customers SET portal_last_login = NOW() WHERE id = $1`
	_, err := r.db.Exec(query, customerID)
	return err
}

// SetCustomerPortalAccess define o acesso ao portal e senha para um cliente
func (r *CRMRepository) SetCustomerPortalAccess(customerID, passwordHash string, hasAccess bool) error {
	query := `
		UPDATE crm_customers 
		SET password_hash = $1, 
		    has_portal_access = $2,
		    portal_created_at = CASE 
		        WHEN portal_created_at IS NULL THEN NOW() 
		        ELSE portal_created_at 
		    END
		WHERE id = $3
	`
	_, err := r.db.Exec(query, passwordHash, hasAccess, customerID)
	return err
}

// UpdateCustomerPassword atualiza apenas a senha do cliente
func (r *CRMRepository) UpdateCustomerPassword(customerID, passwordHash string) error {
	query := `
		UPDATE crm_customers 
		SET password_hash = $1
		WHERE id = $2
	`
	_, err := r.db.Exec(query, passwordHash, customerID)
	return err
}

// UpdateCustomerLogo atualiza apenas o logo do cliente
func (r *CRMRepository) UpdateCustomerLogo(customerID, tenantID, logoURL string) error {
	query := `
		UPDATE crm_customers 
		SET logo_url = $1
		WHERE id = $2 AND tenant_id = $3
	`
	_, err := r.db.Exec(query, logoURL, customerID, tenantID)
	return err
}

// GetCustomerByEmailAndTenant checks if a customer with the given email exists for the tenant
func (r *CRMRepository) GetCustomerByEmailAndTenant(email string, tenantID string) (*domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, phone, company, position,
			   address, city, state, zip_code, country, notes, tags,
			   is_active, created_by, created_at, updated_at
		FROM crm_customers
		WHERE LOWER(email) = LOWER($1) AND tenant_id = $2
		LIMIT 1
	`

	var c domain.CRMCustomer
	err := r.db.QueryRow(query, email, tenantID).Scan(
		&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
		&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
		&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil // Not found is not an error
	}
	if err != nil {
		return nil, err
	}

	return &c, nil
}

// TenantExists checks if a tenant with the given ID exists
func (r *CRMRepository) TenantExists(tenantID string) (bool, error) {
	query := `SELECT EXISTS(SELECT 1 FROM tenants WHERE id = $1 AND is_active = true)`
	var exists bool
	err := r.db.QueryRow(query, tenantID).Scan(&exists)
	return exists, err
}

// EnableCustomerPortalAccess habilita o acesso ao portal para um cliente (usado na aprovação)
func (r *CRMRepository) EnableCustomerPortalAccess(customerID string) error {
	query := `
		UPDATE crm_customers 
		SET has_portal_access = true,
		    portal_created_at = COALESCE(portal_created_at, NOW())
		WHERE id = $1
	`
	_, err := r.db.Exec(query, customerID)
	return err
}

// GetCustomerByCPF checks if a customer with the given CPF exists for the tenant
func (r *CRMRepository) GetCustomerByCPF(cpf string, tenantID string) (*domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, phone, company, position,
			   address, city, state, zip_code, country, notes, tags,
			   is_active, created_by, created_at, updated_at
		FROM crm_customers
		WHERE tenant_id = $1 AND notes LIKE '%"cpf":"' || $2 || '"%'
		LIMIT 1
	`

	var c domain.CRMCustomer
	err := r.db.QueryRow(query, tenantID, cpf).Scan(
		&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
		&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
		&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return &c, nil
}

// GetCustomerByCNPJ checks if a customer with the given CNPJ exists for the tenant
func (r *CRMRepository) GetCustomerByCNPJ(cnpj string, tenantID string) (*domain.CRMCustomer, error) {
	query := `
		SELECT id, tenant_id, name, email, phone, company, position,
			   address, city, state, zip_code, country, notes, tags,
			   is_active, created_by, created_at, updated_at
		FROM crm_customers
		WHERE tenant_id = $1 AND notes LIKE '%"cnpj":"' || $2 || '"%'
		LIMIT 1
	`

	var c domain.CRMCustomer
	err := r.db.QueryRow(query, tenantID, cnpj).Scan(
		&c.ID, &c.TenantID, &c.Name, &c.Email, &c.Phone, &c.Company, &c.Position,
		&c.Address, &c.City, &c.State, &c.ZipCode, &c.Country, &c.Notes, pq.Array(&c.Tags),
		&c.IsActive, &c.CreatedBy, &c.CreatedAt, &c.UpdatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return &c, nil
}

func (r *CRMRepository) GetLeadsByListID(listID string) ([]domain.CRMLead, error) {
	query := `
		SELECT l.id, l.tenant_id, l.customer_id, l.funnel_id, l.stage_id, l.name, l.email, l.phone, 
		       l.source, l.source_meta, l.status, COALESCE(l.notes, ''), l.tags, 
		       l.is_active, COALESCE(l.created_by::text, '') as created_by, l.created_at, l.updated_at
		FROM crm_leads l
		INNER JOIN crm_lead_lists ll ON l.id = ll.lead_id
		WHERE ll.list_id = $1
		ORDER BY l.created_at DESC
	`

	rows, err := r.db.Query(query, listID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var leads []domain.CRMLead
	for rows.Next() {
		var l domain.CRMLead
		var sourceMeta []byte
		err := rows.Scan(
			&l.ID, &l.TenantID, &l.CustomerID, &l.FunnelID, &l.StageID, &l.Name, &l.Email, &l.Phone,
			&l.Source, &sourceMeta, &l.Status, &l.Notes, pq.Array(&l.Tags),
			&l.IsActive, &l.CreatedBy, &l.CreatedAt, &l.UpdatedAt,
		)
		if err != nil {
			log.Printf("Error scanning lead from list: %v", err)
			continue
		}
		if sourceMeta != nil {
			l.SourceMeta = sourceMeta
		}
		leads = append(leads, l)
	}

	return leads, nil
}

// ==================== FUNNELS & STAGES ====================

func (r *CRMRepository) CreateFunnel(funnel *domain.CRMFunnel) error {
	query := `
		INSERT INTO crm_funnels (id, tenant_id, name, description, is_default)
		VALUES ($1, $2, $3, $4, $5)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(query, funnel.ID, funnel.TenantID, funnel.Name, funnel.Description, funnel.IsDefault).
		Scan(&funnel.CreatedAt, &funnel.UpdatedAt)
}

func (r *CRMRepository) GetFunnelsByTenant(tenantID string) ([]domain.CRMFunnel, error) {
	query := `SELECT id, tenant_id, name, COALESCE(description, ''), is_default, created_at, updated_at FROM crm_funnels WHERE tenant_id = $1 ORDER BY created_at ASC`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var funnels []domain.CRMFunnel
	for rows.Next() {
		var f domain.CRMFunnel
		if err := rows.Scan(&f.ID, &f.TenantID, &f.Name, &f.Description, &f.IsDefault, &f.CreatedAt, &f.UpdatedAt); err != nil {
			return nil, err
		}
		funnels = append(funnels, f)
	}
	return funnels, nil
}

func (r *CRMRepository) GetFunnelByID(id, tenantID string) (*domain.CRMFunnel, error) {
	query := `SELECT id, tenant_id, name, COALESCE(description, ''), is_default, created_at, updated_at FROM crm_funnels WHERE id = $1 AND tenant_id = $2`
	var f domain.CRMFunnel
	err := r.db.QueryRow(query, id, tenantID).Scan(&f.ID, &f.TenantID, &f.Name, &f.Description, &f.IsDefault, &f.CreatedAt, &f.UpdatedAt)
	if err != nil {
		return nil, err
	}
	return &f, nil
}

func (r *CRMRepository) UpdateFunnel(funnel *domain.CRMFunnel) error {
	query := `UPDATE crm_funnels SET name = $1, description = $2, is_default = $3, updated_at = CURRENT_TIMESTAMP WHERE id = $4 AND tenant_id = $5`
	_, err := r.db.Exec(query, funnel.Name, funnel.Description, funnel.IsDefault, funnel.ID, funnel.TenantID)
	return err
}

func (r *CRMRepository) DeleteFunnel(id, tenantID string) error {
	query := `DELETE FROM crm_funnels WHERE id = $1 AND tenant_id = $2`
	_, err := r.db.Exec(query, id, tenantID)
	return err
}

func (r *CRMRepository) CreateFunnelStage(stage *domain.CRMFunnelStage) error {
	query := `
		INSERT INTO crm_funnel_stages (id, funnel_id, name, description, color, order_index)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(query, stage.ID, stage.FunnelID, stage.Name, stage.Description, stage.Color, stage.OrderIndex).
		Scan(&stage.CreatedAt, &stage.UpdatedAt)
}

func (r *CRMRepository) GetStagesByFunnelID(funnelID string) ([]domain.CRMFunnelStage, error) {
	query := `SELECT id, funnel_id, name, COALESCE(description, ''), color, order_index, created_at, updated_at FROM crm_funnel_stages WHERE funnel_id = $1 ORDER BY order_index ASC`
	rows, err := r.db.Query(query, funnelID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var stages []domain.CRMFunnelStage
	for rows.Next() {
		var s domain.CRMFunnelStage
		if err := rows.Scan(&s.ID, &s.FunnelID, &s.Name, &s.Description, &s.Color, &s.OrderIndex, &s.CreatedAt, &s.UpdatedAt); err != nil {
			return nil, err
		}
		stages = append(stages, s)
	}
	return stages, nil
}

func (r *CRMRepository) UpdateFunnelStage(stage *domain.CRMFunnelStage) error {
	query := `UPDATE crm_funnel_stages SET name = $1, description = $2, color = $3, order_index = $4, updated_at = CURRENT_TIMESTAMP WHERE id = $5`
	_, err := r.db.Exec(query, stage.Name, stage.Description, stage.Color, stage.OrderIndex, stage.ID)
	return err
}

func (r *CRMRepository) DeleteFunnelStage(id string) error {
	query := `DELETE FROM crm_funnel_stages WHERE id = $1`
	_, err := r.db.Exec(query, id)
	return err
}

func (r *CRMRepository) UpdateLeadStage(leadID, tenantID, funnelID, stageID string) error {
	query := `UPDATE crm_leads SET funnel_id = $1, stage_id = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3 AND tenant_id = $4`
	_, err := r.db.Exec(query, funnelID, stageID, leadID, tenantID)
	return err
}

func (r *CRMRepository) EnsureDefaultFunnel(tenantID string) (string, error) {
	// Check if tenant already has a funnel
	var funnelID string
	query := `SELECT id FROM crm_funnels WHERE tenant_id = $1 LIMIT 1`
	err := r.db.QueryRow(query, tenantID).Scan(&funnelID)
	if err == nil {
		return funnelID, nil
	}

	// If not, create default using the function we defined in migration
	query = `SELECT create_default_crm_funnel($1)`
	err = r.db.QueryRow(query, tenantID).Scan(&funnelID)
	return funnelID, err
}


