# Progressed Chart Generation Flow

## Overview
The progressed chart uses the **kerykeion** library (not "keisky") to generate SVG astrological charts. The flow is:
- **Frontend**: User submits birth data → API request
- **Backend**: Calculate natal & progressed charts using kerykeion → Generate SVG wheels → Return data
- **Frontend**: Display chart SVG images + planet data + aspects

---

## 1. BACKEND: API Endpoint

### File: `backend/main.py` (Line 533)

```python
@app.post("/calculators/progressed-chart")
def create_progressed_chart(data: ProgressedDetails):
    try:
        result = generate_progressed_chart(
            data.year,
            data.month,
            data.day,
            data.hour,
            data.minute,
            data.second,
            data.latitude,
            data.longitude,
            data.timezone,
        )
        return result

    except Exception as e:
        return JSONResponse(
            {"success": False, "error": str(e)},
            status_code=500,
        )
```

### Request Model

```python
class ProgressedDetails(BaseModel):
    year: int
    month: int
    day: int
    hour: int
    minute: int
    second: int = 0
    latitude: float
    longitude: float
    timezone: float = DEFAULT_TIMEZONE  # default 5.5 for India
```

---

## 2. BACKEND: Chart Generation Logic

### File: `backend/progressed_chart.py`

#### **Step 1: Calculate Progressed Date**
```python
def calculate_progressed_date(year, month, day, hour, minute, second=0):
    """
    Secondary progression: 1 year of life = 1 day after birth
    Uses today's date automatically
    """
    birth_dt = datetime(year, month, day, hour, minute, second)
    today = datetime.now()
    
    age_in_years = (today - birth_dt).total_seconds() / (365.2425 * 24 * 60 * 60)
    progressed_days = int(age_in_years)
    
    progressed_dt = birth_dt + timedelta(days=progressed_days)
    
    return {
        "birth_datetime": birth_dt,
        "current_datetime": today,
        "age": age_in_years,
        "progressed_datetime": progressed_dt,
    }
```

#### **Step 2: Calculate Both Charts**
```python
def calculate_single_chart(year, month, day, hour, minute, second, latitude, longitude, timezone):
    """
    Calculates planet positions for a specific date/time/location
    """
    chart = calculate_planets(year, month, day, hour, minute, second, latitude, longitude, timezone)
    
    return {
        "planets": convert_planets_dict_to_list(chart["planets"]),
        "angles": chart.get("angles", {}),
        "houses": chart.get("houses", []),
        "moon_phase": chart.get("moon_phase"),
    }
```

#### **Step 3: Generate SVG Charts using Kerykeion**
```python
from kerykeion import AstrologicalSubject, KerykeionChartSVG

# Create Natal Chart
natal_subject = AstrologicalSubject(
    name="Natal",
    year=birth_dt.year,
    month=birth_dt.month,
    day=birth_dt.day,
    hour=birth_dt.hour,
    minute=birth_dt.minute,
    lat=latitude,
    lng=longitude,
    tz_str="Asia/Kolkata"
)

# Generate SVG wheel
natal_chart = KerykeionChartSVG(natal_subject, new_output_directory=charts_dir)
natal_chart.makeSVG()  # Generates SVG file

# Extract just the wheel (without full chart)
extract_wheel(natal_full_path, natal_wheel_path)

# Repeat for Progressed Chart
progressed_subject = AstrologicalSubject(
    name="Progressed",
    year=progressed_dt.year,
    month=progressed_dt.month,
    day=progressed_dt.day,
    hour=progressed_dt.hour,
    minute=progressed_dt.minute,
    lat=latitude,
    lng=longitude,
    tz_str="Asia/Kolkata"
)

progressed_chart = KerykeionChartSVG(progressed_subject, new_output_directory=charts_dir)
progressed_chart.makeSVG()
extract_wheel(progressed_full_path, progressed_wheel_path)
```

#### **Step 4: Calculate Aspects Between Natal & Progressed**
```python
def calculate_progressed_aspects(natal_planets, progressed_planets):
    """
    Compares progressed planets WITH natal planets
    Returns aspects with proper identification
    """
    major = []
    minor = []
    
    for prog in progressed_planets:
        for nat in natal_planets:
            diff = angle_diff(prog["longitude"], nat["longitude"])
            
            for asp in aspects_def:
                orb = abs(diff - asp["angle"])
                
                if orb <= asp["orb"]:
                    row = {
                        "progressed_planet": prog["planet"],  # PROGRESSED PLANET FIRST
                        "natal_planet": nat["planet"],        # NATAL PLANET SECOND
                        "planet1": prog["planet"],
                        "planet2": nat["planet"],
                        "aspect": asp["name"],
                        "symbol": asp["symbol"],
                        "orb": format_orb(orb),
                        "orb_value": round(orb, 4),
                        "type": asp["type"],  # "major" or "minor"
                    }
                    
                    if asp["type"] == "major":
                        major.append(row)
                    else:
                        minor.append(row)
                    break
    
    return {
        "major_aspects": major,
        "minor_aspects": minor,
    }
```

#### **Step 5: Return Complete Response**
```python
def generate_progressed_chart(...):
    # ... calculations ...
    
    return {
        "birth_date": birth_dt.strftime("%Y-%m-%d"),
        "birth_time": birth_dt.strftime("%H:%M:%S"),
        "current_date": current_dt.strftime("%Y-%m-%d"),
        "current_time": current_dt.strftime("%H:%M:%S"),
        "age": round(progressed_info["age"], 2),
        "progressed_date": progressed_dt.strftime("%Y-%m-%d"),
        "progressed_time": progressed_dt.strftime("%H:%M:%S"),
        "house_system": "Placidus",
        
        # SVG CHART URLs (stored in /charts/progressedchart/)
        "natal_chart": f"/charts/progressedchart/{os.path.basename(natal_wheel_path)}",
        "progressed_chart": f"/charts/progressedchart/{os.path.basename(progressed_wheel_path)}",
        
        # PLANET DATA
        "natal_planets": natal["planets"],
        "progressed_planets": progressed["planets"],
        
        # ASPECTS
        "major_aspects": aspects["major_aspects"],
        "minor_aspects": aspects["minor_aspects"],
    }
```

---

## 3. FRONTEND: How to Fetch

### File: `frontend/src/pages/ProgressedChart.jsx`

```jsx
async function handleSubmit(e) {
  e.preventDefault();
  setLoading(true);

  const randomId = Math.floor(100000 + Math.random() * 900000);

  // Convert 12-hour to 24-hour format
  const time24 = to24Hour(form.hour, form.ampm);

  // Prepare request payload
  const payload = {
    year: form.year,
    month: form.month,
    day: form.day,
    hour: time24,
    minute: form.minute,
    latitude: form.latitude,
    longitude: form.longitude,
    timezone: form.timezone,
  };

  try {
    // STEP 1: Send request to backend
    const res = await fetch(`${API_URL}/calculators/progressed-chart`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });

    const data = await res.json();

    if (!res.ok) {
      throw new Error(data.error || "Progressed chart API failed");
    }

    // STEP 2: Combine response with form data
    const finalData = {
      id: randomId,
      details: {
        birthdate: `${form.year}-${String(form.month).padStart(2, "0")}-${String(form.day).padStart(2, "0")}`,
        time: `${form.hour}:${form.minute} ${form.ampm}`,
        place: form.place,
        latitude: form.latitude,
        longitude: form.longitude,
      },
      ...data,  // Contains: natal_chart, progressed_chart, planets, aspects, dates
    };

    // STEP 3: Save to localStorage
    localStorage.setItem(`progressed_chart_${randomId}`, JSON.stringify(finalData));

    // STEP 4: Navigate to result page
    navigate(`/progressed-chart/${randomId}`);

  } catch (err) {
    alert(err.message);
    console.error(err);
  } finally {
    setLoading(false);
  }
}
```

---

## 4. FRONTEND: Display the Chart

### File: `frontend/src/pages/Result_Show/ProgressedChartResult.jsx`

```jsx
export default function ProgressedChartResult() {
  const { id } = useParams();
  const [data, setData] = useState(null);

  useEffect(() => {
    // Retrieve from localStorage
    const stored = localStorage.getItem(`progressed_chart_${id}`);
    
    if (stored) {
      const parsed = JSON.parse(stored);
      setData(parsed);
    }
  }, [id]);

  if (!data) {
    return <div>Loading...</div>;
  }

  return (
    <main className="progressed-result-page">
      <div className="progressed-result-container">
        
        {/* DISPLAY NATAL CHART SVG */}
        {data.natal_chart && (
          <section>
            <h2>Natal Chart</h2>
            <img src={data.natal_chart} alt="Natal Chart" />
          </section>
        )}

        {/* DISPLAY PROGRESSED CHART SVG */}
        {data.progressed_chart && (
          <section>
            <h2>Progressed Chart</h2>
            <img src={data.progressed_chart} alt="Progressed Chart" />
          </section>
        )}

        {/* DISPLAY PLANETS */}
        <section>
          <h3>Natal Planets</h3>
          <div>
            {(data.natal_planets || []).map((planet, i) => (
              <div key={i}>
                {planet.planet}: {planet.longitude}° ({planet.sign})
              </div>
            ))}
          </div>
        </section>

        <section>
          <h3>Progressed Planets</h3>
          <div>
            {(data.progressed_planets || []).map((planet, i) => (
              <div key={i}>
                {planet.planet}: {planet.longitude}° ({planet.sign})
              </div>
            ))}
          </div>
        </section>

        {/* DISPLAY MAJOR ASPECTS */}
        <section>
          <h3>Major Aspects (Progressed → Natal)</h3>
          <div>
            {(data.major_aspects || []).map((aspect, i) => (
              <div key={i}>
                {aspect.progressed_planet} {aspect.symbol} {aspect.natal_planet}
                <br />
                Orb: {aspect.orb}
              </div>
            ))}
          </div>
        </section>

        {/* DISPLAY MINOR ASPECTS */}
        <section>
          <h3>Minor Aspects (Progressed → Natal)</h3>
          <div>
            {(data.minor_aspects || []).map((aspect, i) => (
              <div key={i}>
                {aspect.progressed_planet} {aspect.symbol} {aspect.natal_planet}
                <br />
                Orb: {aspect.orb}
              </div>
            ))}
          </div>
        </section>

      </div>
    </main>
  );
}
```

---

## 5. API Response Example

```json
{
  "birth_date": "2003-11-18",
  "birth_time": "12:00:00",
  "current_date": "2026-05-18",
  "current_time": "14:30:00",
  "age": 22.52,
  "progressed_date": "2025-12-28",
  "progressed_time": "12:00:00",
  "house_system": "Placidus",
  
  "natal_chart": "/charts/progressedchart/Natal_Chart_20031118_55_2281_7083.svg",
  "progressed_chart": "/charts/progressedchart/Progressed_Chart_20031118_55_2281_7083.svg",
  
  "natal_planets": [
    {
      "planet": "Sun",
      "sign": "Scorpio",
      "degree": 25.48,
      "house": 10,
      "longitude": 235.48
    },
    ...more planets
  ],
  
  "progressed_planets": [
    {
      "planet": "Sun",
      "sign": "Capricorn",
      "degree": 8.22,
      "house": 12,
      "longitude": 278.22
    },
    ...more planets
  ],
  
  "major_aspects": [
    {
      "progressed_planet": "Sun",
      "natal_planet": "Moon",
      "aspect": "Conjunction",
      "symbol": "☌",
      "orb": "2° 15'",
      "orb_value": 2.25,
      "type": "major"
    }
  ],
  
  "minor_aspects": [
    {
      "progressed_planet": "Mercury",
      "natal_planet": "Venus",
      "aspect": "Semisextile",
      "symbol": "⚺",
      "orb": "1° 30'",
      "orb_value": 1.5,
      "type": "minor"
    }
  ]
}
```

---

## 6. How to Check Natal vs Progressed

```jsx
// Check if first planet is progressed and second is natal
const aspect = majorAspects[0];

if (aspect.progressed_planet && aspect.natal_planet) {
  // This is definitely a progressed-natal aspect
  console.log(`${aspect.progressed_planet} (progressed) aspects ${aspect.natal_planet} (natal)`);
}

// Filter by type
const isNatal = (aspect) => aspect.type === "major" && aspect.progressed_planet;
const isMajor = (aspect) => aspect.type === "major";
const isMinor = (aspect) => aspect.type === "minor";
```

---

## 7. File Locations

| Component | File |
|-----------|------|
| Backend API | `backend/main.py` (line 533) |
| Chart Generation | `backend/progressed_chart.py` |
| Aspect Calculation | `backend/progressed_chart.py` (line 103) |
| Frontend Input Form | `frontend/src/pages/ProgressedChart.jsx` |
| Frontend Display | `frontend/src/pages/Result_Show/ProgressedChartResult.jsx` |
| SVG Output | `backend/charts/progressedchart/` |

---

## 8. Key Points

✅ **Kerykeion Library** - Generates astrological SVG charts automatically  
✅ **Secondary Progression** - 1 day after birth = 1 year of life  
✅ **Dual Charts** - Natal chart + Progressed chart both generated as SVG  
✅ **Aspect Identification** - `progressed_planet` field shows progressed, `natal_planet` shows natal  
✅ **Static Files** - Charts served from `/charts/progressedchart/` endpoint
