package psql

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/gabehf/koito/internal/models"
	"github.com/gabehf/koito/internal/repository"
	"github.com/jackc/pgx/v5/pgtype"
)

const searchItemLimit = 8
const substringSearchLength = 6

func (d *Psql) SearchArtists(ctx context.Context, q string) ([]*models.Artist, error) {
	if len(q) < substringSearchLength {
		rows, err := d.q.SearchArtistsBySubstring(ctx, repository.SearchArtistsBySubstringParams{
			Column1: pgtype.Text{String: q, Valid: true},
			Limit:   searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchArtist: SearchArtistsBySubstring: %w", err)
		}
		ret := make([]*models.Artist, len(rows))
		for i, row := range rows {
			ret[i] = &models.Artist{
				ID:    row.ID,
				MbzID: row.MusicBrainzID,
				Name:  row.Name,
				Image: row.Image,
			}
		}
		return ret, nil
	} else {
		rows, err := d.q.SearchArtists(ctx, repository.SearchArtistsParams{
			Similarity: q,
			Limit:      searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchArtist: SearchArtists: %w", err)
		}
		ret := make([]*models.Artist, len(rows))
		for i, row := range rows {
			ret[i] = &models.Artist{
				ID:    row.ID,
				MbzID: row.MusicBrainzID,
				Name:  row.Name,
				Image: row.Image,
			}
		}
		return ret, nil
	}
}

func (d *Psql) SearchAlbums(ctx context.Context, q string) ([]*models.Album, error) {
	if len(q) < substringSearchLength {
		rows, err := d.q.SearchReleasesBySubstring(ctx, repository.SearchReleasesBySubstringParams{
			Column1: pgtype.Text{String: q, Valid: true},
			Limit:   searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchAlbums: SearchReleasesBySubstring: %w", err)
		}
		ret := make([]*models.Album, len(rows))
		for i, row := range rows {
			ret[i] = &models.Album{
				ID:             row.ID,
				MbzID:          row.MusicBrainzID,
				Title:          row.Title,
				VariousArtists: row.VariousArtists,
				Image:          row.Image,
			}
			err = json.Unmarshal(row.Artists, &ret[i].Artists)
			if err != nil {
				return nil, fmt.Errorf("SearchAlbums: Unmarshal: %w", err)
			}
		}
		return ret, nil
	} else {
		rows, err := d.q.SearchReleases(ctx, repository.SearchReleasesParams{
			Similarity: q,
			Limit:      searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchAlbums: SearchReleases: %w", err)
		}
		ret := make([]*models.Album, len(rows))
		for i, row := range rows {
			ret[i] = &models.Album{
				ID:             row.ID,
				MbzID:          row.MusicBrainzID,
				Title:          row.Title,
				VariousArtists: row.VariousArtists,
				Image:          row.Image,
			}
			err = json.Unmarshal(row.Artists, &ret[i].Artists)
			if err != nil {
				return nil, fmt.Errorf("SearchAlbums: Unmarshal: %w", err)
			}
		}
		return ret, nil
	}
}

func (d *Psql) SearchTracks(ctx context.Context, q string) ([]*models.Track, error) {
	if len(q) < substringSearchLength {
		rows, err := d.q.SearchTracksBySubstring(ctx, repository.SearchTracksBySubstringParams{
			Column1: pgtype.Text{String: q, Valid: true},
			Limit:   searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchTracks: SearchTracksBySubstring: %w", err)
		}
		ret := make([]*models.Track, len(rows))
		for i, row := range rows {
			ret[i] = &models.Track{
				ID:    row.ID,
				MbzID: row.MusicBrainzID,
				Title: row.Title,
				Image: row.Image,
			}
			err = json.Unmarshal(row.Artists, &ret[i].Artists)
			if err != nil {
				return nil, fmt.Errorf("SearchTracks: Unmarshal: %w", err)
			}
		}
		return ret, nil
	} else {
		rows, err := d.q.SearchTracks(ctx, repository.SearchTracksParams{
			Similarity: q,
			Limit:      searchItemLimit,
		})
		if err != nil {
			return nil, fmt.Errorf("SearchTracks: SearchTracks: %w", err)
		}
		ret := make([]*models.Track, len(rows))
		for i, row := range rows {
			ret[i] = &models.Track{
				ID:    row.ID,
				MbzID: row.MusicBrainzID,
				Title: row.Title,
				Image: row.Image,
			}
			err = json.Unmarshal(row.Artists, &ret[i].Artists)
			if err != nil {
				return nil, fmt.Errorf("SearchTracks: Unmarshal: %w", err)
			}
		}
		return ret, nil
	}
}
