에 의해 nexple, 10 12월, 2025

import React, { useState } from 'react';
import { Search, Music, Play, ExternalLink } from 'lucide-react';

export default function MusicSearch() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState({ spotify: [], soundcloud: [] });
  const [loading, setLoading] = useState(false);

  const searchSpotify = async (searchQuery) => {
    try {
      const response = await fetch("https://api.anthropic.com/v1/messages", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 1000,
          messages: [
            {
              role: "user",
              content: `Search for "${searchQuery}" on Spotify. Return ONLY a JSON array of up to 5 results with this exact structure, no other text:
[{"title": "song name", "artist": "artist name", "url": "spotify link", "image": "image url or empty string"}]`
            }
          ],
          tools: [{
            type: "web_search_20250305",
            name: "web_search"
          }]
        })
      });

      const data = await response.json();
      const text = data.content.map(item => item.type === "text" ? item.text : "").join("");
      const cleaned = text.replace(/```json|```/g, "").trim();
      return JSON.parse(cleaned);
    } catch (err) {
      console.error('Spotify search error:', err);
      return [];
    }
  };

  const searchSoundCloud = async (searchQuery) => {
    try {
      const response = await fetch("https://api.anthropic.com/v1/messages", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 1000,
          messages: [
            {
              role: "user",
              content: `Search for "${searchQuery}" on SoundCloud. Return ONLY a JSON array of up to 5 results with this exact structure, no other text:
[{"title": "track name", "artist": "artist name", "url": "soundcloud link", "image": "image url or empty string"}]`
            }
          ],
          tools: [{
            type: "web_search_20250305",
            name: "web_search"
          }]
        })
      });

      const data = await response.json();
      const text = data.content.map(item => item.type === "text" ? item.text : "").join("");
      const cleaned = text.replace(/```json|```/g, "").trim();
      return JSON.parse(cleaned);
    } catch (err) {
      console.error('SoundCloud search error:', err);
      return [];
    }
  };

  const handleSearch = async () => {
    if (!query.trim()) return;

    setLoading(true);
    setResults({ spotify: [], soundcloud: [] });

    const [spotifyData, soundcloudData] = await Promise.all([
      searchSpotify(query),
      searchSoundCloud(query)
    ]);

    setResults({
      spotify: spotifyData,
      soundcloud: soundcloudData
    });
    setLoading(false);
  };

  const handleKeyPress = (e) => {
    if (e.key === 'Enter') {
      handleSearch();
    }
  };

  const ResultCard = ({ item, platform }) => (
    <div className="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow">
      <div className="flex gap-4">
        {item.image && (
          <img 
            src={item.image} 
            alt={item.title}
            className="w-20 h-20 rounded object-cover"
          />
        )}
        <div className="flex-1 min-w-0">
          <h3 className="font-semibold text-gray-900 truncate">{item.title}</h3>
          <p className="text-sm text-gray-600 truncate">{item.artist}</p>
          <a
            href={item.url}
            target="_blank"
            rel="noopener noreferrer"
            className="inline-flex items-center gap-1 text-sm text-blue-600 hover:text-blue-800 mt-2"
          >
            <ExternalLink size={14} />
            {platform}에서 듣기
          </a>
        </div>
      </div>
    </div>
  );

  return (
    <div className="min-h-screen bg-gradient-to-br from-purple-50 to-blue-50 p-6">
      <div className="max-w-6xl mx-auto">
        <div className="text-center mb-8">
          <div className="flex items-center justify-center gap-2 mb-2">
            <Music className="text-purple-600" size={32} />
            <h1 className="text-3xl font-bold text-gray-900">음악 통합 검색</h1>
          </div>
          <p className="text-gray-600">Spotify와 SoundCloud를 동시에 검색하세요</p>
        </div>

        <div className="mb-8">
          <div className="flex gap-2 max-w-2xl mx-auto">
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
              <input
                type="text"
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                onKeyPress={handleKeyPress}
                placeholder="노래 제목, 아티스트 이름 입력..."
                className="w-full pl-10 pr-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-purple-500 focus:border-transparent"
              />
            </div>
            <button
              onClick={handleSearch}
              disabled={loading}
              className="px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 disabled:bg-gray-400 transition-colors font-medium"
            >
              {loading ? '검색 중...' : '검색'}
            </button>
          </div>
        </div>

        {loading && (
          <div className="text-center py-12">
            <div className="inline-block animate-spin rounded-full h-12 w-12 border-4 border-gray-300 border-t-purple-600"></div>
            <p className="mt-4 text-gray-600">결과를 가져오는 중...</p>
          </div>
        )}

        {!loading && (results.spotify.length > 0 || results.soundcloud.length > 0) && (
          <div className="grid md:grid-cols-2 gap-8">
            <div>
              <div className="flex items-center gap-2 mb-4">
                <div className="w-8 h-8 bg-green-500 rounded-full flex items-center justify-center">
                  <Play size={16} className="text-white" />
                </div>
                <h2 className="text-xl font-bold text-gray-900">Spotify</h2>
              </div>
              <div className="space-y-4">
                {results.spotify.length > 0 ? (
                  results.spotify.map((item, idx) => (
                    <ResultCard key={idx} item={item} platform="Spotify" />
                  ))
                ) : (
                  <p className="text-gray-500 text-center py-8">결과가 없습니다</p>
                )}
              </div>
            </div>

            <div>
              <div className="flex items-center gap-2 mb-4">
                <div className="w-8 h-8 bg-orange-500 rounded-full flex items-center justify-center">
                  <Play size={16} className="text-white" />
                </div>
                <h2 className="text-xl font-bold text-gray-900">SoundCloud</h2>
              </div>
              <div className="space-y-4">
                {results.soundcloud.length > 0 ? (
                  results.soundcloud.map((item, idx) => (
                    <ResultCard key={idx} item={item} platform="SoundCloud" />
                  ))
                ) : (
                  <p className="text-gray-500 text-center py-8">결과가 없습니다</p>
                )}
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}