import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ColorState, SketchPicker } from 'react-color';
import { Doc } from '../../fields/Doc';
import { Id } from '../../fields/FieldSymbols';
import { BoolCast, Cast, StrCast } from '../../fields/Types';
import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
import { MainViewModal } from '../views/MainViewModal';
import { FontIconBox } from '../views/nodes/button/FontIconBox';
import { DragManager } from './DragManager';
import { GroupManager } from './GroupManager';
import './SettingsManager.scss';
import './ReportManager.scss';
import { undoBatch } from './UndoManager';
import { Octokit } from "@octokit/core";
import { CheckBox } from '../views/search/CheckBox';
import ReactLoading from 'react-loading';
import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;

@observer
export class ReportManager extends React.Component<{}> {
    public static Instance: ReportManager;
    @observable private isOpen = false;

    private octokit: Octokit;

    @observable public issues: any[] = [];
    @action setIssues = action((issues: any[]) => { this.issues = issues; });
    
    // undefined is the default - null is if the user is making an issue
    @observable public selectedIssue: any = undefined;
    @action setSelectedIssue = action((issue: any) => { this.selectedIssue = issue; });

    // only get the open issues
    @observable public shownIssues = this.issues.filter(issue => issue.state === 'open');
    
    public updateIssueSearch = action((query: string = '') => {
        if (query === '') {
            this.shownIssues = this.issues.filter(issue => issue.state === 'open');
            return;
        }
       this.shownIssues = this.issues.filter(issue => issue.title.toLowerCase().includes(query.toLowerCase()));
    });

    constructor(props: {}) {
        super(props);
        ReportManager.Instance = this;

        this.octokit = new Octokit({
            auth: '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'
        });
    }

    public close = action(() => (this.isOpen = false));
    public open = action(() => {
        if (this.issues.length === 0) {
            // load in the issues if not already loaded
            this.getAllIssues()
                .then(issues => {
                    this.setIssues(issues);
                    this.updateIssueSearch();
                })
                .catch(err => console.log(err));
        }
        (this.isOpen = true)
    });

    @observable private bugTitle = '';
    @action setBugTitle = action((title: string) => { this.bugTitle = title; });
    @observable private bugDescription = '';
    @action setBugDescription = action((description: string) => { this.bugDescription = description; });
    @observable private bugType = '';
    @action setBugType = action((type: string) => { this.bugType = type; });
    @observable private bugPriority = '';
    @action setBugPriority = action((priortiy: string) => { this.bugPriority = priortiy; });

    // private toGithub = false;
    // will always be set to true - no alterntive option yet
    private toGithub = true;

    private formatTitle = (title: string, userEmail: string) => `${title} - ${userEmail.replace('@brown.edu', '')}`; 

    public async getAllIssues() : Promise<any[]> {
        const res = await this.octokit.request('GET /repos/{owner}/{repo}/issues', {
            owner: 'brown-dash',
            repo: 'Dash-Web',
        });

        // 200 status means success
        if (res.status === 200) {
            return res.data;
        } else {
            throw new Error('Error getting issues');
        }
    }

    // turns an upload link into a servable link
    // ex: 
    // C: /Users/dash/Documents/GitHub/Dash-Web/src/server/public/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2.png
    // -> http://localhost:1050/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2_l.png
    private fileLinktoServerLink = (fileLink: string) => {
        const serverUrl = 'https://browndash.com/';

        const regex = 'public'
        const publicIndex = fileLink.indexOf(regex) + regex.length;

        const finalUrl = `${serverUrl}${fileLink.substring(publicIndex + 1).replace('.', '_l.')}`;
        return finalUrl;
    }

    public async reportIssue() {
        if (this.bugTitle === '' || this.bugDescription === ''
            || this.bugType === '' || this.bugPriority === '') {
            alert('Please fill out all required fields to report an issue.');
            return;
        }

        if (this.toGithub) {

            const formattedLinks = (this.fileLinks ?? []).map(this.fileLinktoServerLink)
            
            const req = await this.octokit.request('POST /repos/{owner}/{repo}/issues', {
                owner: 'brown-dash',
                repo: 'Dash-Web',
                title: this.formatTitle(this.bugTitle, Doc.CurrentUserEmail),
                body: `${this.bugDescription} \n\nfiles:\n${formattedLinks.join('\n')}`,
                labels: [
                    'from-dash-app',
                    this.bugType,
                    this.bugPriority
                ]
            });

            // 201 status means success
            if (req.status !== 201) {
                alert('Error creating issue on github.');
                // on error, don't close the modal
                return;
            }
        }
        else {
            // if not going to github issues, not sure what to do yet...
        }

        // if we're down here, then we're good to go. reset the fields.
        this.setBugTitle('');
        this.setBugDescription('');
        // this.toGithub = false;
        this.setFileLinks([]);
        this.setBugType('');
        this.setBugPriority('');
        this.close();
    }

    @observable public fileLinks: any = [];
    @action setFileLinks = action((links: any) => { this.fileLinks = links; });

    private getServerPath = (link: any) => { return link.result.accessPaths.agnostic.server }

    private uploadFiles = (input: any) => {
        // keep null while uploading
        this.setFileLinks(null);
        // upload the files to the server
        if (input.files && input.files.length !== 0) {
            const fileArray: File[] = Array.from(input.files);
            (Networking.UploadFilesToServer(fileArray)).then(links => {
                console.log('finshed uploading', links.map(this.getServerPath));
                this.setFileLinks((links ?? []).map(this.getServerPath));
            })
        }
        
    }


    private renderIssue = (issue: any) => {

        const isReportingIssue = issue === null;

        return isReportingIssue ?
            // report issue
            (<div className="settings-content">
                <h3 style={{ 'textDecoration': 'underline'}}>Report an Issue</h3>
                <label>Please leave a title for the bug.</label><br />
                <input type="text" placeholder='title' onChange={(e) => this.setBugTitle(e.target.value)} required/>
                <br />
                <label>Please leave a description for the bug and how it can be recreated.</label>
                <textarea placeholder='description' onChange={(e) => this.setBugDescription(e.target.value)} required/>
                <br />
                {/* {<label>Send to github issues? </label>
                <input type="checkbox" onChange={(e) => this.toGithub = e.target.checked} />
                <br /> } */}

                <label>Please label the issue</label>
                <div className='flex-select'>
                    <select name="bugType" onChange={e => this.bugType = e.target.value}>
                    <option value="" disabled selected>Type</option>
                    <option value="bug">Bug</option>
                    <option value="cosmetic">Poor Design or Cosmetic</option>
                    <option value="documentation">Poor Documentation</option>
                    </select>

                    <select name="bigPriority" onChange={e => this.bugPriority = e.target.value}>
                        <option value="" disabled selected>Priority</option>
                        <option value="priority-low">Low</option>
                        <option value="priority-medium">Medium</option>
                        <option value="priority-high">High</option>
                    </select>
                </div>


                <div>
                    <label>Upload media that shows the bug (optional)</label>
                    <input type="file" name="file" multiple accept='audio/*, video/*, image/*' onChange={e => this.uploadFiles(e.target)}/>
                </div>
                <br />

                <button onClick={() => this.reportIssue()} disabled={this.fileLinks === null} style={{ backgroundColor: this.fileLinks === null ? 'grey' : '' }}>{this.fileLinks === null ? 'Uploading...' : 'Submit'}</button>
            </div>)
            :
            // view issue
            (
            <div className='issue-container'>
                <h5 style={{'textAlign': "left"}}><a href={issue.html_url} target="_blank">Issue #{issue.number}</a></h5>
                <div className='issue-title'>
                    {issue.title}
                </div>
                <ReactMarkdown children={issue.body} className='issue-body' linkTarget={"_blank"} remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]} />
            </div>
        );
    }

    private showReportIssueScreen = () => {
        this.setSelectedIssue(null);
    }

    private closeReportIssueScreen = () => {
        this.setSelectedIssue(undefined);
    }

    private get reportInterface() {

        const isReportingIssue = this.selectedIssue === null;

        return (
            <div className="settings-interface">
                <div className='issue-list-wrapper'>
                    <h3>Current Issues</h3>
                    <input type="text" placeholder='search issues' onChange={(e => this.updateIssueSearch(e.target.value))}></input><br />
                    {this.issues.length === 0 ? <ReactLoading className='loading-center'/> : this.shownIssues.map(issue => <div className='issue-list' key={issue.number} onClick={() => this.setSelectedIssue(issue)}>{issue.title}</div>)}

                    {/* <div className="settings-user">
                        <button onClick={() => this.getAllIssues().then(issues => this.issues = issues)}>Poll Issues</button>
                    </div> */}
                </div>
                    
                <div className="close-button" onClick={this.close}>
                    <FontAwesomeIcon icon={'times'} color="black" size={'lg'} />
                </div>

                <div className="issue-content" style={{'paddingTop' : this.selectedIssue === undefined ? '50px' : 'inherit'}}>
                    {this.selectedIssue === undefined ? "no issue selected" : this.renderIssue(this.selectedIssue)}
                </div>

                <div className='report-issue-fab'>
                    <span className='report-disclaimer' hidden={!isReportingIssue}>Note: issue reporting is not anonymous.</span>
                    <button
                        onClick={() => isReportingIssue ? this.closeReportIssueScreen() : this.showReportIssueScreen()}
                    >{isReportingIssue ? 'Cancel' : 'Report New Issue'}</button>
                </div>


            </div>
        );
    }

    render() {
        return (
            <MainViewModal
                contents={this.reportInterface}
                isDisplayed={this.isOpen}
                interactive={true}
                closeOnExternalClick={this.close}
                dialogueBoxStyle={{ width: 'auto', height: '500px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }}
            />
        );
    }
}
