import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error

# 1. Load Data
file_path = r"C:\Users\jack8\OneDrive\stock cow ai\data\stock price.csv"
df = pd.read_csv(file_path, parse_dates=['Date'])

# 2. Data Cleaning: Remove commas and convert to numeric
cols_to_clean = ['Volume (Lots)', 'Buy', 'Sell', 'Net Buy/Sell (Lots)']

for col in cols_to_clean:
    # Remove commas and convert to numeric
    df[col] = df[col].astype(str).str.replace(',', '').astype(float)

# Alternatively, using pd.to_numeric with error handling
# for col in cols_to_clean:
#     df[col] = pd.to_numeric(df[col].str.replace(',', ''), errors='coerce')

# 3. Sort and Indexing
df.sort_values('Date', inplace=True)
df.set_index('Date', inplace=True)

# 4. Handling Missing Values
print("Missing values before cleaning:", df.isnull().sum())
df.dropna(inplace=True)  # Or use df.fillna(method='ffill') for forward fill
print("Missing values after cleaning:", df.isnull().sum())

# 5. Feature Selection
features = ['Opening Price', 'Highest Price', 'Lowest Price', 'Volume (Lots)', 'Buy', 'Sell', 'Net Buy/Sell (Lots)']
target = 'Closing Price'

X = df[features]
y = df[target]

# 6. Scaling the Data
scaler_X = MinMaxScaler(feature_range=(0, 1))
X_scaled = scaler_X.fit_transform(X)

scaler_y = MinMaxScaler(feature_range=(0, 1))
y_scaled = scaler_y.fit_transform(y.values.reshape(-1, 1))

# 7. Creating Sequences for LSTM
def create_sequences(X, y, time_steps=10):
    Xs, ys = [], []
    for i in range(len(X) - time_steps):
        Xs.append(X[i:(i + time_steps)])
        ys.append(y[i + time_steps])
    return np.array(Xs), np.array(ys)

time_steps = 10
X_seq, y_seq = create_sequences(X_scaled, y_scaled, time_steps)

print(f"Shape of X_seq: {X_seq.shape}")  # (num_samples, time_steps, num_features)
print(f"Shape of y_seq: {y_seq.shape}")  # (num_samples, 1)

# 8. Train-Test Split
X_train, X_test, y_train, y_test = train_test_split(
    X_seq, y_seq, test_size=0.2, shuffle=False
)

print(f"Training samples: {X_train.shape[0]}")
print(f"Testing samples: {X_test.shape[0]}")

# 9. Building the LSTM Model
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], X_train.shape[2])))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(units=25))
model.add(Dense(units=1))  # Output layer

model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()

# 10. Training the Model
epochs = 50
batch_size = 32

history = model.fit(
    X_train, y_train,
    epochs=epochs,
    batch_size=batch_size,
    validation_data=(X_test, y_test),
    verbose=1
)

# 11. Evaluating the Model
# Plot Training and Validation Loss
plt.figure(figsize=(12, 6))
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title('Loss Over Epochs')
plt.xlabel('Epoch')
plt.ylabel('Mean Squared Error')
plt.legend()
plt.show()

# Making Predictions
y_pred_scaled = model.predict(X_test)
y_pred = scaler_y.inverse_transform(y_pred_scaled)
y_test_actual = scaler_y.inverse_transform(y_test)

# Plot Actual vs Predicted
plt.figure(figsize=(14, 7))
plt.plot(y_test_actual, color='blue', label='Actual Closing Price')
plt.plot(y_pred, color='red', label='Predicted Closing Price')
plt.title('Actual vs Predicted Closing Prices')
plt.xlabel('Time')
plt.ylabel('Closing Price')
plt.legend()
plt.show()

# Calculating Performance Metrics
mse = mean_squared_error(y_test_actual, y_pred)
mae = mean_absolute_error(y_test_actual, y_pred)
print(f"Mean Squared Error: {mse}")
print(f"Mean Absolute Error: {mae}")

###我希望把test的20%改成0，我要讓train訓練完成後預測20%的資料，不要有參照，要不然我20%給真實的資料他會就預測相同的，我給0他就會預測0，這樣不行