package repository

import (
	"aggios-app/backend/internal/domain"
	"database/sql"
	"github.com/lib/pq"
)

type ERPRepository struct {
	db *sql.DB
}

func NewERPRepository(db *sql.DB) *ERPRepository {
	return &ERPRepository{db: db}
}

// ==================== FINANCE: CATEGORIES ====================

func (r *ERPRepository) CreateFinancialCategory(cat *domain.FinancialCategory) error {
	query := `
		INSERT INTO erp_financial_categories (id, tenant_id, name, type, color, is_active)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(
		query,
		cat.ID, cat.TenantID, cat.Name, cat.Type, cat.Color, cat.IsActive,
	).Scan(&cat.CreatedAt, &cat.UpdatedAt)
}

func (r *ERPRepository) GetFinancialCategoriesByTenant(tenantID string) ([]domain.FinancialCategory, error) {
	query := `
		SELECT id, tenant_id, name, type, color, is_active, created_at, updated_at
		FROM erp_financial_categories
		WHERE tenant_id = $1
		ORDER BY name ASC
	`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var categories []domain.FinancialCategory
	for rows.Next() {
		var c domain.FinancialCategory
		err := rows.Scan(&c.ID, &c.TenantID, &c.Name, &c.Type, &c.Color, &c.IsActive, &c.CreatedAt, &c.UpdatedAt)
		if err != nil {
			return nil, err
		}
		categories = append(categories, c)
	}
	return categories, nil
}

// ==================== FINANCE: BANK ACCOUNTS ====================

func (r *ERPRepository) CreateBankAccount(acc *domain.BankAccount) error {
	query := `
		INSERT INTO erp_bank_accounts (id, tenant_id, name, bank_name, initial_balance, current_balance, is_active)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(
		query,
		acc.ID, acc.TenantID, acc.Name, acc.BankName, acc.InitialBalance, acc.InitialBalance, acc.IsActive,
	).Scan(&acc.CreatedAt, &acc.UpdatedAt)
}

func (r *ERPRepository) GetBankAccountsByTenant(tenantID string) ([]domain.BankAccount, error) {
	query := `
		SELECT id, tenant_id, name, bank_name, initial_balance, current_balance, is_active, created_at, updated_at
		FROM erp_bank_accounts
		WHERE tenant_id = $1
		ORDER BY name ASC
	`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var accounts []domain.BankAccount
	for rows.Next() {
		var a domain.BankAccount
		err := rows.Scan(&a.ID, &a.TenantID, &a.Name, &a.BankName, &a.InitialBalance, &a.CurrentBalance, &a.IsActive, &a.CreatedAt, &a.UpdatedAt)
		if err != nil {
			return nil, err
		}
		accounts = append(accounts, a)
	}
	return accounts, nil
}

// ==================== ENTITIES: CUSTOMERS & SUPPLIERS ====================

func (r *ERPRepository) CreateEntity(e *domain.Entity) error {
	query := `
		INSERT INTO erp_entities (id, tenant_id, name, document, email, phone, type, status, address, city, state, zip, notes)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(
		query,
		e.ID, e.TenantID, e.Name, e.Document, e.Email, e.Phone, e.Type, e.Status, e.Address, e.City, e.State, e.Zip, e.Notes,
	).Scan(&e.CreatedAt, &e.UpdatedAt)
}

func (r *ERPRepository) GetEntitiesByTenant(tenantID string, entityType string) ([]domain.Entity, error) {
	query := `
		SELECT id, tenant_id, name, document, email, phone, type, status, address, city, state, zip, notes, created_at, updated_at
		FROM erp_entities
		WHERE tenant_id = $1
	`
	var args []interface{}
	args = append(args, tenantID)

	if entityType != "" {
		query += " AND (type = $2 OR type = 'both')"
		args = append(args, entityType)
	}

	query += " ORDER BY name ASC"

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

	var entities []domain.Entity
	for rows.Next() {
		var e domain.Entity
		err := rows.Scan(
			&e.ID, &e.TenantID, &e.Name, &e.Document, &e.Email, &e.Phone, &e.Type, &e.Status, &e.Address, &e.City, &e.State, &e.Zip, &e.Notes, &e.CreatedAt, &e.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		entities = append(entities, e)
	}
	return entities, nil
}

// ==================== FINANCE: TRANSACTIONS ====================

func (r *ERPRepository) CreateTransaction(t *domain.FinancialTransaction) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	query := `
		INSERT INTO erp_financial_transactions (
			id, tenant_id, account_id, category_id, entity_id, crm_customer_id, company_id, description, amount, type, status, due_date, payment_date, payment_method, attachments, created_by
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
		RETURNING created_at, updated_at
	`
	err = tx.QueryRow(
		query,
		t.ID, t.TenantID, t.AccountID, t.CategoryID, t.EntityID, t.CRMCustomerID, t.CompanyID, t.Description, t.Amount, t.Type, t.Status, t.DueDate, t.PaymentDate, t.PaymentMethod, pq.Array(t.Attachments), t.CreatedBy,
	).Scan(&t.CreatedAt, &t.UpdatedAt)
	if err != nil {
		return err
	}

	// Update balance if paid
	if t.Status == "paid" && t.AccountID != nil {
		balanceQuery := ""
		if t.Type == "income" {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance + $1 WHERE id = $2"
		} else {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance - $1 WHERE id = $2"
		}
		_, err = tx.Exec(balanceQuery, t.Amount, t.AccountID)
		if err != nil {
			return err
		}
	}

	return tx.Commit()
}

func (r *ERPRepository) GetTransactionsByTenant(tenantID string) ([]domain.FinancialTransaction, error) {
	query := `
		SELECT id, tenant_id, account_id, category_id, entity_id, crm_customer_id, company_id, description, amount, type, status, due_date, payment_date, payment_method, attachments, created_by, created_at, updated_at
		FROM erp_financial_transactions
		WHERE tenant_id = $1
		ORDER BY created_at DESC
	`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var transactions []domain.FinancialTransaction
	for rows.Next() {
		var t domain.FinancialTransaction
		err := rows.Scan(
			&t.ID, &t.TenantID, &t.AccountID, &t.CategoryID, &t.EntityID, &t.CRMCustomerID, &t.CompanyID, &t.Description, &t.Amount, &t.Type, &t.Status, &t.DueDate, &t.PaymentDate, &t.PaymentMethod, pq.Array(&t.Attachments), &t.CreatedBy, &t.CreatedAt, &t.UpdatedAt,
		)
		if err != nil {
			return nil, err
		}
		transactions = append(transactions, t)
	}
	return transactions, nil
}

// ==================== PRODUCTS ====================

func (r *ERPRepository) CreateProduct(p *domain.Product) error {
	query := `
		INSERT INTO erp_products (id, tenant_id, name, sku, description, price, cost_price, type, stock_quantity, is_active)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
		RETURNING created_at, updated_at
	`
	return r.db.QueryRow(
		query,
		p.ID, p.TenantID, p.Name, p.SKU, p.Description, p.Price, p.CostPrice, p.Type, p.StockQuantity, p.IsActive,
	).Scan(&p.CreatedAt, &p.UpdatedAt)
}

func (r *ERPRepository) GetProductsByTenant(tenantID string) ([]domain.Product, error) {
	query := `
		SELECT id, tenant_id, name, sku, description, price, cost_price, type, stock_quantity, is_active, created_at, updated_at
		FROM erp_products
		WHERE tenant_id = $1
		ORDER BY name ASC
	`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var products []domain.Product
	for rows.Next() {
		var p domain.Product
		err := rows.Scan(&p.ID, &p.TenantID, &p.Name, &p.SKU, &p.Description, &p.Price, &p.CostPrice, &p.Type, &p.StockQuantity, &p.IsActive, &p.CreatedAt, &p.UpdatedAt)
		if err != nil {
			return nil, err
		}
		products = append(products, p)
	}
	return products, nil
}

// ==================== ORDERS ====================

func (r *ERPRepository) CreateOrder(o *domain.Order, items []domain.OrderItem) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	orderQuery := `
		INSERT INTO erp_orders (id, tenant_id, customer_id, entity_id, status, total_amount, notes, created_by)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
		RETURNING created_at, updated_at
	`
	err = tx.QueryRow(
		orderQuery,
		o.ID, o.TenantID, o.CustomerID, o.EntityID, o.Status, o.TotalAmount, o.Notes, o.CreatedBy,
	).Scan(&o.CreatedAt, &o.UpdatedAt)
	if err != nil {
		return err
	}

	itemQuery := `
		INSERT INTO erp_order_items (id, order_id, product_id, quantity, unit_price, total_price)
		VALUES ($1, $2, $3, $4, $5, $6)
	`
	for _, item := range items {
		_, err = tx.Exec(itemQuery, item.ID, o.ID, item.ProductID, item.Quantity, item.UnitPrice, item.TotalPrice)
		if err != nil {
			return err
		}

		// Update stock if product
		stockQuery := "UPDATE erp_products SET stock_quantity = stock_quantity - $1 WHERE id = $2 AND type = 'product'"
		_, err = tx.Exec(stockQuery, item.Quantity, item.ProductID)
		if err != nil {
			return err
		}
	}

	return tx.Commit()
}

func (r *ERPRepository) GetOrdersByTenant(tenantID string) ([]domain.Order, error) {
	query := `
		SELECT id, tenant_id, customer_id, status, total_amount, notes, created_by, created_at, updated_at
		FROM erp_orders
		WHERE tenant_id = $1
		ORDER BY created_at DESC
	`
	rows, err := r.db.Query(query, tenantID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var orders []domain.Order
	for rows.Next() {
		var o domain.Order
		err := rows.Scan(&o.ID, &o.TenantID, &o.CustomerID, &o.Status, &o.TotalAmount, &o.Notes, &o.CreatedBy, &o.CreatedAt, &o.UpdatedAt)
		if err != nil {
			return nil, err
		}
		orders = append(orders, o)
	}
	return orders, nil
}
func (r *ERPRepository) UpdateTransaction(t *domain.FinancialTransaction) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Get old transaction to adjust balance
	var oldT domain.FinancialTransaction
	err = tx.QueryRow(`
		SELECT amount, type, status, account_id 
		FROM erp_financial_transactions 
		WHERE id = $1 AND tenant_id = $2`, t.ID, t.TenantID).
		Scan(&oldT.Amount, &oldT.Type, &oldT.Status, &oldT.AccountID)
	if err != nil {
		return err
	}

	// Falls back to old type if not provided in request
	if t.Type == "" {
		t.Type = oldT.Type
	}

	// Reverse old balance impact
	if oldT.Status == "paid" && oldT.AccountID != nil {
		balanceQuery := ""
		if oldT.Type == "income" {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance - $1 WHERE id = $2"
		} else {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance + $1 WHERE id = $2"
		}
		_, err = tx.Exec(balanceQuery, oldT.Amount, oldT.AccountID)
		if err != nil {
			return err
		}
	}

	query := `
		UPDATE erp_financial_transactions
		SET description = $1, amount = $2, type = $3, status = $4, due_date = $5, payment_date = $6, 
		    category_id = $7, entity_id = $8, crm_customer_id = $9, company_id = $10, account_id = $11, payment_method = $12, updated_at = NOW()
		WHERE id = $13 AND tenant_id = $14
	`
	_, err = tx.Exec(query, 
		t.Description, t.Amount, t.Type, t.Status, t.DueDate, t.PaymentDate, 
		t.CategoryID, t.EntityID, t.CRMCustomerID, t.CompanyID, t.AccountID, t.PaymentMethod, 
		t.ID, t.TenantID)
	if err != nil {
		return err
	}

	// Apply new balance impact
	if t.Status == "paid" && t.AccountID != nil {
		balanceQuery := ""
		if t.Type == "income" {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance + $1 WHERE id = $2"
		} else {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance - $1 WHERE id = $2"
		}
		_, err = tx.Exec(balanceQuery, t.Amount, t.AccountID)
		if err != nil {
			return err
		}
	}

	return tx.Commit()
}

func (r *ERPRepository) DeleteTransaction(id, tenantID string) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Adjust balance before delete
	var t domain.FinancialTransaction
	err = tx.QueryRow(`
		SELECT amount, type, status, account_id 
		FROM erp_financial_transactions 
		WHERE id = $1 AND tenant_id = $2`, id, tenantID).
		Scan(&t.Amount, &t.Type, &t.Status, &t.AccountID)
	if err != nil {
		return err
	}

	if t.Status == "paid" && t.AccountID != nil {
		balanceQuery := ""
		if t.Type == "income" {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance - $1 WHERE id = $2"
		} else {
			balanceQuery = "UPDATE erp_bank_accounts SET current_balance = current_balance + $1 WHERE id = $2"
		}
		_, err = tx.Exec(balanceQuery, t.Amount, t.AccountID)
		if err != nil {
			return err
		}
	}

	_, err = tx.Exec("DELETE FROM erp_financial_transactions WHERE id = $1 AND tenant_id = $2", id, tenantID)
	if err != nil {
		return err
	}

	return tx.Commit()
}


func (r *ERPRepository) UpdateEntity(e *domain.Entity) error {
	query := `
		UPDATE erp_entities
		SET name = $1, document = $2, email = $3, phone = $4, type = $5, status = $6, 
		    address = $7, city = $8, state = $9, zip = $10, notes = $11, updated_at = NOW()
		WHERE id = $12 AND tenant_id = $13
	`
	_, err := r.db.Exec(query, e.Name, e.Document, e.Email, e.Phone, e.Type, e.Status, e.Address, e.City, e.State, e.Zip, e.Notes, e.ID, e.TenantID)
	return err
}

func (r *ERPRepository) DeleteEntity(id, tenantID string) error {
	_, err := r.db.Exec("DELETE FROM erp_entities WHERE id = $1 AND tenant_id = $2", id, tenantID)
	return err
}

func (r *ERPRepository) UpdateProduct(p *domain.Product) error {
	query := `
		UPDATE erp_products
		SET name = $1, sku = $2, description = $3, price = $4, cost_price = $5, 
		    type = $6, stock_quantity = $7, is_active = $8, updated_at = NOW()
		WHERE id = $9 AND tenant_id = $10
	`
	_, err := r.db.Exec(query, p.Name, p.SKU, p.Description, p.Price, p.CostPrice, p.Type, p.StockQuantity, p.IsActive, p.ID, p.TenantID)
	return err
}

func (r *ERPRepository) DeleteProduct(id, tenantID string) error {
	_, err := r.db.Exec("DELETE FROM erp_products WHERE id = $1 AND tenant_id = $2", id, tenantID)
	return err
}

func (r *ERPRepository) UpdateBankAccount(a *domain.BankAccount) error {
	query := `
		UPDATE erp_bank_accounts
		SET name = $1, bank_name = $2, initial_balance = $3, is_active = $4, updated_at = NOW()
		WHERE id = $5 AND tenant_id = $6
	`
	_, err := r.db.Exec(query, a.Name, a.BankName, a.InitialBalance, a.IsActive, a.ID, a.TenantID)
	return err
}

func (r *ERPRepository) DeleteBankAccount(id, tenantID string) error {
	_, err := r.db.Exec("DELETE FROM erp_bank_accounts WHERE id = $1 AND tenant_id = $2", id, tenantID)
	return err
}

func (r *ERPRepository) DeleteOrder(id, tenantID string) error {
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Deleta os itens do pedido primeiro
	_, err = tx.Exec("DELETE FROM erp_order_items WHERE order_id = $1", id)
	if err != nil {
		return err
	}

	// Deleta o pedido
	_, err = tx.Exec("DELETE FROM erp_orders WHERE id = $1 AND tenant_id = $2", id, tenantID)
	if err != nil {
		return err
	}

	return tx.Commit()
}
