package handler

import (
	"fmt"
	"net/http"
	"portfolio-tracker/internal/model"
	"portfolio-tracker/internal/service"
	"portfolio-tracker/internal/web/templates"
	"strconv"
	"strings"
	"time"

	"github.com/a-h/templ"
)

func PortfolioHandler(w http.ResponseWriter, r *http.Request) {
	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in PortfolioHandler: %v\n", err)
	}

	portfolios := getUserPortfolios(username)

	component := templates.Portfolio(auth, username, portfolios)
	templ.Handler(component).ServeHTTP(w, r)
}

func PortfolioDetailHandler(w http.ResponseWriter, r *http.Request) {
	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in PortfolioDetailHandler: %v\n", err)
	}

	// Extract portfolio ID from URL path
	path := r.URL.Path
	portfolioIDStr := strings.TrimPrefix(path, "/portfolio/")
	portfolioID, err := strconv.ParseUint(portfolioIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Portfolio-ID", http.StatusBadRequest)
		return
	}

	// Get user
	var user model.User
	if err := DB.Where("username = ?", username).First(&user).Error; err != nil {
		http.Error(w, "Benutzer nicht gefunden", http.StatusUnauthorized)
		return
	}

	// Get portfolio with activities
	var portfolio model.Portfolio
	if err := DB.Preload("Activities").Where("id = ? AND user_id = ?", portfolioID, user.ID).First(&portfolio).Error; err != nil {
		http.Error(w, "Portfolio nicht gefunden oder keine Berechtigung", http.StatusForbidden)
		return
	}

	// Calculate positions
	fmt.Printf("DEBUG: Starting position calculation for portfolio %d with %d activities\n", portfolio.ID, len(portfolio.Activities))
	positionCalculator := service.NewPositionCalculator()
	positions, positionSummary, err := positionCalculator.CalculatePositions(portfolio)
	if err != nil {
		fmt.Printf("Error calculating positions: %v\n", err)
		// Continue with empty positions rather than failing
		positions = []model.Position{}
		positionSummary = model.PositionSummary{
			Currency:    portfolio.BaseCurrency,
			LastUpdated: time.Now(),
		}
	}

	fmt.Printf("DEBUG: Position calculation completed. Found %d positions\n", len(positions))
	for i, pos := range positions {
		fmt.Printf("DEBUG: Position %d: %s - Shares: %.4f, Open: %v\n", i+1, pos.Stock, pos.Shares, pos.IsOpen())
	}
	fmt.Printf("DEBUG: Position summary - Total Value: %.2f, Total Cost: %.2f\n", positionSummary.TotalValue, positionSummary.TotalCostBasis)

	// Get all user portfolios for navigation
	portfolios := getUserPortfolios(username)

	component := templates.PortfolioDetail(auth, username, portfolio, portfolios, positions, positionSummary)
	templ.Handler(component).ServeHTTP(w, r)
}

func CreatePortfolioHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Nur POST erlaubt", http.StatusMethodNotAllowed)
		return
	}

	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in CreatePortfolioHandler: %v\n", err)
	}

	if !auth {
		http.Error(w, "Nicht angemeldet", http.StatusUnauthorized)
		return
	}

	if username == "" {
		http.Error(w, "Benutzer nicht gefunden", http.StatusBadRequest)
		return
	}

	// Get form values
	name := r.FormValue("name")
	baseCurrency := r.FormValue("base_currency")
	description := r.FormValue("description")

	// Basic validation
	if name == "" || baseCurrency == "" {
		http.Error(w, "Name und Basiswährung sind erforderlich", http.StatusBadRequest)
		return
	}

	// Get user from database
	var user model.User
	if err := DB.Where("username = ?", username).First(&user).Error; err != nil {
		http.Error(w, "Benutzer nicht gefunden", http.StatusBadRequest)
		return
	}

	// Create new portfolio
	portfolio := model.Portfolio{
		UserID:       user.ID,
		Name:         name,
		BaseCurrency: baseCurrency,
		Description:  description,
	}

	if err := DB.Create(&portfolio).Error; err != nil {
		fmt.Printf("Error creating portfolio: %v\n", err)
		http.Error(w, "Fehler beim Erstellen des Portfolios", http.StatusInternalServerError)
		return
	}

	fmt.Printf("Portfolio created successfully: ID=%d, Name=%s, User=%s\n", portfolio.ID, portfolio.Name, username)

	// Redirect to the new portfolio
	http.Redirect(w, r, fmt.Sprintf("/portfolio/%d", portfolio.ID), http.StatusSeeOther)
}

func PortfolioTransactionHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Nur POST erlaubt", http.StatusMethodNotAllowed)
		return
	}

	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in PortfolioTransactionHandler: %v\n", err)
	}

	if !auth {
		http.Error(w, "Nicht angemeldet", http.StatusUnauthorized)
		return
	}

	if username == "" {
		http.Error(w, "Benutzer nicht gefunden", http.StatusBadRequest)
		return
	}

	// Get form values
	portfolioIDStr := r.FormValue("portfolio_id")
	transactionType := r.FormValue("type")
	stock := r.FormValue("stock")
	amountStr := r.FormValue("amount")
	priceStr := r.FormValue("price")
	dateStr := r.FormValue("date")
	note := r.FormValue("note")

	// Basic validation
	if transactionType == "" || stock == "" || amountStr == "" || priceStr == "" || dateStr == "" {
		http.Error(w, "Alle Pflichtfelder müssen ausgefüllt werden", http.StatusBadRequest)
		return
	}

	// Parse form values
	amount, err := strconv.ParseFloat(amountStr, 64)
	if err != nil {
		http.Error(w, "Ungültiger Betrag", http.StatusBadRequest)
		return
	}

	price, err := strconv.ParseFloat(priceStr, 64)
	if err != nil {
		http.Error(w, "Ungültiger Preis", http.StatusBadRequest)
		return
	}

	date, err := time.Parse("2006-01-02", dateStr)
	if err != nil {
		http.Error(w, "Ungültiges Datum", http.StatusBadRequest)
		return
	}

	portfolioID, err := strconv.ParseUint(portfolioIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Portfolio-ID", http.StatusBadRequest)
		return
	}

	// Verify portfolio belongs to user
	var portfolio model.Portfolio
	if err := DB.Joins("User").Where("portfolios.id = ? AND User.username = ?", portfolioID, username).First(&portfolio).Error; err != nil {
		http.Error(w, "Portfolio nicht gefunden oder keine Berechtigung", http.StatusBadRequest)
		return
	}

	// Fetch stock currency from Yahoo Finance
	stockCurrency, err := getStockCurrency(stock)
	if err != nil {
		fmt.Printf("Warning: Could not fetch currency for stock %s: %v. Using portfolio base currency.\n", stock, err)
		stockCurrency = portfolio.BaseCurrency
	}

	fmt.Printf("Stock %s currency: %s\n", stock, stockCurrency)

	// Handle GBp (pence) to GBP (pounds) conversion
	// If the stock is quoted in pence, convert price to pounds
	if stockCurrency == "GBp" {
		price = price / 100.0
		stockCurrency = "GBP"
		fmt.Printf("Converted GBp price %.2f to GBP price %.2f\n", price*100, price)
	}

	// Create activity
	activity := model.Activity{
		PortfolioID: uint(portfolioID),
		Stock:       stock,
		Type:        model.ActivityType(transactionType),
		Amount:      amount,
		Price:       price,
		Currency:    stockCurrency, // Use the fetched stock currency
		Date:        date,
		Note:        note,
	}

	if err := DB.Create(&activity).Error; err != nil {
		fmt.Printf("Error creating activity: %v\n", err)
		http.Error(w, "Fehler beim Speichern der Transaktion", http.StatusInternalServerError)
		return
	}

	fmt.Printf("Activity created successfully: ID=%d, Type=%s, Stock=%s, Currency=%s, Portfolio=%d\n",
		activity.ID, activity.Type, activity.Stock, activity.Currency, activity.PortfolioID)

	// Redirect to portfolio page
	http.Redirect(w, r, fmt.Sprintf("/portfolio/%d", portfolioID), http.StatusSeeOther)
}

func EditTransactionHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Nur POST erlaubt", http.StatusMethodNotAllowed)
		return
	}

	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in EditTransactionHandler: %v\n", err)
	}

	if !auth {
		http.Error(w, "Nicht angemeldet", http.StatusUnauthorized)
		return
	}

	if username == "" {
		http.Error(w, "Benutzer nicht gefunden", http.StatusBadRequest)
		return
	}

	// Get form values
	activityIDStr := r.FormValue("activity_id")
	portfolioIDStr := r.FormValue("portfolio_id")
	transactionType := r.FormValue("type")
	stock := r.FormValue("stock")
	amountStr := r.FormValue("amount")
	priceStr := r.FormValue("price")
	dateStr := r.FormValue("date")
	note := r.FormValue("note")

	// Basic validation
	if activityIDStr == "" || transactionType == "" || stock == "" || amountStr == "" || priceStr == "" || dateStr == "" {
		http.Error(w, "Alle Pflichtfelder müssen ausgefüllt werden", http.StatusBadRequest)
		return
	}

	// Parse form values
	activityID, err := strconv.ParseUint(activityIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Aktivitäts-ID", http.StatusBadRequest)
		return
	}

	portfolioID, err := strconv.ParseUint(portfolioIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Portfolio-ID", http.StatusBadRequest)
		return
	}

	amount, err := strconv.ParseFloat(amountStr, 64)
	if err != nil {
		http.Error(w, "Ungültiger Betrag", http.StatusBadRequest)
		return
	}

	price, err := strconv.ParseFloat(priceStr, 64)
	if err != nil {
		http.Error(w, "Ungültiger Preis", http.StatusBadRequest)
		return
	}

	date, err := time.Parse("2006-01-02", dateStr)
	if err != nil {
		http.Error(w, "Ungültiges Datum", http.StatusBadRequest)
		return
	}

	// Get existing activity and verify ownership using subquery
	var activity model.Activity
	if err := DB.Where("id = ? AND portfolio_id IN (SELECT id FROM portfolios WHERE user_id = (SELECT id FROM users WHERE username = ?))",
		activityID, username).First(&activity).Error; err != nil {
		http.Error(w, "Aktivität nicht gefunden oder keine Berechtigung", http.StatusBadRequest)
		return
	}

	// Verify the activity belongs to the specified portfolio
	if activity.PortfolioID != uint(portfolioID) {
		http.Error(w, "Aktivität gehört nicht zu diesem Portfolio", http.StatusBadRequest)
		return
	}

	// Get portfolio to access base currency
	var portfolio model.Portfolio
	if err := DB.Where("id = ?", portfolioID).First(&portfolio).Error; err != nil {
		http.Error(w, "Portfolio nicht gefunden", http.StatusBadRequest)
		return
	}

	// Fetch stock currency from Yahoo Finance (or use portfolio base currency as fallback)
	stockCurrency, err := getStockCurrency(stock)
	if err != nil {
		fmt.Printf("Warning: Could not fetch currency for stock %s: %v. Using portfolio base currency.\n", stock, err)
		stockCurrency = portfolio.BaseCurrency
	}

	// Handle GBp (pence) to GBP (pounds) conversion
	// If the stock is quoted in pence, convert price to pounds
	if stockCurrency == "GBp" {
		price = price / 100.0
		stockCurrency = "GBP"
		fmt.Printf("Converted GBp price %.2f to GBP price %.2f\n", price*100, price)
	}

	// Update activity fields
	activity.Type = model.ActivityType(transactionType)
	activity.Stock = stock
	activity.Amount = amount
	activity.Price = price
	activity.Currency = stockCurrency
	activity.Date = date
	activity.Note = note

	// Save updated activity
	if err := DB.Save(&activity).Error; err != nil {
		fmt.Printf("Error updating activity: %v\n", err)
		http.Error(w, "Fehler beim Aktualisieren der Transaktion", http.StatusInternalServerError)
		return
	}

	fmt.Printf("Activity updated successfully: ID=%d, Type=%s, Stock=%s, Portfolio=%d\n",
		activity.ID, activity.Type, activity.Stock, activity.PortfolioID)

	// Redirect to portfolio page
	http.Redirect(w, r, fmt.Sprintf("/portfolio/%d", portfolioID), http.StatusSeeOther)
}

func DeleteTransactionHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Nur POST erlaubt", http.StatusMethodNotAllowed)
		return
	}

	auth, username, err := getSessionInfo(r)
	if err != nil {
		fmt.Printf("Session error in DeleteTransactionHandler: %v\n", err)
	}

	if !auth {
		http.Error(w, "Nicht angemeldet", http.StatusUnauthorized)
		return
	}

	if username == "" {
		http.Error(w, "Benutzer nicht gefunden", http.StatusBadRequest)
		return
	}

	// Get form values
	activityIDStr := r.FormValue("activity_id")
	portfolioIDStr := r.FormValue("portfolio_id")

	// Basic validation
	if activityIDStr == "" || portfolioIDStr == "" {
		http.Error(w, "Aktivitäts-ID und Portfolio-ID sind erforderlich", http.StatusBadRequest)
		return
	}

	// Parse form values
	activityID, err := strconv.ParseUint(activityIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Aktivitäts-ID", http.StatusBadRequest)
		return
	}

	portfolioID, err := strconv.ParseUint(portfolioIDStr, 10, 32)
	if err != nil {
		http.Error(w, "Ungültige Portfolio-ID", http.StatusBadRequest)
		return
	}

	// Get existing activity and verify ownership using subquery
	var activity model.Activity
	if err := DB.Where("id = ? AND portfolio_id IN (SELECT id FROM portfolios WHERE user_id = (SELECT id FROM users WHERE username = ?))",
		activityID, username).First(&activity).Error; err != nil {
		http.Error(w, "Aktivität nicht gefunden oder keine Berechtigung", http.StatusBadRequest)
		return
	}

	// Verify the activity belongs to the specified portfolio
	if activity.PortfolioID != uint(portfolioID) {
		http.Error(w, "Aktivität gehört nicht zu diesem Portfolio", http.StatusBadRequest)
		return
	}

	// Delete the activity
	if err := DB.Delete(&activity).Error; err != nil {
		fmt.Printf("Error deleting activity: %v\n", err)
		http.Error(w, "Fehler beim Löschen der Transaktion", http.StatusInternalServerError)
		return
	}

	fmt.Printf("Activity deleted successfully: ID=%d, Type=%s, Stock=%s, Portfolio=%d\n",
		activity.ID, activity.Type, activity.Stock, activity.PortfolioID)

	// Redirect to portfolio page
	http.Redirect(w, r, fmt.Sprintf("/portfolio/%d", portfolioID), http.StatusSeeOther)
}
